diff --git a/packages/ai-tools/dist/lib/tools/fs copy.d.ts b/packages/ai-tools/dist/lib/tools/fs copy.d.ts new file mode 100644 index 00000000..5852c674 --- /dev/null +++ b/packages/ai-tools/dist/lib/tools/fs copy.d.ts @@ -0,0 +1,3 @@ +import { IKBotTask } from '../../types.js'; +export declare const decode_base64: (base64: string) => string; +export declare const tools: (target: string, options: IKBotTask) => Array; diff --git a/packages/ai-tools/dist/lib/tools/fs copy.js b/packages/ai-tools/dist/lib/tools/fs copy.js new file mode 100644 index 00000000..4ee35c1f --- /dev/null +++ b/packages/ai-tools/dist/lib/tools/fs copy.js @@ -0,0 +1,432 @@ +import * as path from 'path'; +import { sync as rm } from '@polymech/fs/remove'; +import { isString } from '@polymech/core/primitives'; +import { sync as write } from '@polymech/fs/write'; +import { sync as read } from '@polymech/fs/read'; +import { sync as rename } from '@polymech/fs/rename'; +import { sync as exists } from '@polymech/fs/exists'; +import { sanitize } from "@polymech/fs/utils"; +import { filesEx } from '@polymech/commons'; +import { toolLogger } from '../../index.js'; +import { EXCLUDE_GLOB } from '../../constants.js'; +import { glob } from 'glob'; +const isBase64 = (str) => { + // 1. Quick checks for length & allowed characters: + // - Must be multiple of 4 in length + // - Must match Base64 charset (A-Z, a-z, 0-9, +, /) plus optional "=" padding + if (!str || str.length % 4 !== 0) { + return false; + } + const base64Regex = /^[A-Za-z0-9+/]+={0,2}$/; + if (!base64Regex.test(str)) { + return false; + } + // 2. Attempt decode–re-encode to confirm validity: + try { + const decoded = atob(str); // Decode from Base64 + const reencoded = btoa(decoded); // Re-encode to Base64 + // Compare the re-encoded string to original + return reencoded === str; + } + catch { + return false; + } +}; +export const decode_base64 = (base64) => { + try { + if (!isBase64(base64)) { + return base64; + } + return Buffer.from(base64, 'base64').toString('utf-8'); + } + catch (error) { + throw new Error('Failed to decode base64 string'); + } +}; +// Helper function for smart Base64 decoding +const decodeContentSmart = (content, logger, identifier) => { + if (!content || typeof content !== 'string') { + return content; // Return original content if null, undefined, or not a string + } + const lines = content.split(/\r?\n/); + const processedLines = lines.map(line => { + const trimmedLine = line.trim(); + if (!trimmedLine) { + return ''; // Preserve empty lines between potential blocks but decode the blocks themselves + } + try { + // Attempt to decode Base64 + const decodedLine = Buffer.from(trimmedLine, 'base64').toString('utf-8'); + // Validate if it was actually Base64 by re-encoding + const reEncodedLine = Buffer.from(decodedLine, 'utf-8').toString('base64'); + // Revised Validation Check: + // Compare original trimmed line with re-encoded line. + // Allow for potential padding differences by checking both exact match and no-pad match. + const originalNoPad = trimmedLine.replace(/={1,2}$/, ''); + const reEncodedNoPad = reEncodedLine.replace(/={1,2}$/, ''); + if (reEncodedLine === trimmedLine || reEncodedNoPad === originalNoPad) { + logger.debug(`Successfully decoded Base64 line for ${identifier}`); + return decodedLine; + } + // If validation fails, treat as plain text + logger.debug(`Re-encoding mismatch for ${identifier}. Original: '${trimmedLine}', Re-encoded: '${reEncodedLine}', using original trimmed line.`); + return trimmedLine; + } + catch (decodeError) { + // If decoding throws an error, assume it's plain text + // Use debug level as this is expected for non-base64 lines + logger.debug(`Base64 decoding failed for line in ${identifier}, assuming plain text. Line: ${trimmedLine}`); + return trimmedLine; // Return original trimmed line + } + }); + // Join the processed lines back together + return processedLines.join('\n'); +}; +export const tools = (target, options) => { + const logger = toolLogger('fs', options); + return [ + { + type: 'function', + function: { + name: 'list_files', + description: 'List all files in a directory', + parameters: { + type: 'object', + properties: { + directory: { type: 'string' }, + pattern: { type: 'string', optional: true } + }, + required: ['directory'] + }, + function: async (params) => { + try { + const directory = path.join(target, sanitize(params.directory)); + if (!exists(directory)) { + logger.debug(`Tool::ListFiles Directory ${directory} does not exist`); + return []; + } + let pattern = params.pattern || '**/*'; + logger.debug(`Tool::ListFiles Listing files in ${directory} with pattern ${pattern}`); + pattern = [ + ...EXCLUDE_GLOB, + pattern + ]; + const ret = await glob(pattern, { + cwd: directory, + absolute: false, + ignore: EXCLUDE_GLOB + }); + return ret; + } + catch (error) { + logger.error('Error listing files', error); + throw error; + } + }, + parse: JSON.parse + } + }, + { + type: 'function', + function: { + name: 'read_files', + description: 'Reads files in a directory with a given pattern', + parameters: { + type: 'object', + properties: { + directory: { type: 'string' }, + pattern: { type: 'string', optional: true } + }, + required: ['directory'] + }, + function: async (params) => { + try { + const pattern = params.pattern || '**/*'; + let entries = filesEx(target, pattern); + let ret = entries.map((entry) => { + try { + let content = read(entry); + return { + path: path.relative(target, entry).replace(/\\/g, '/'), + content: content.toString() + }; + } + catch (error) { + logger.error(`Error reading file ${entry}:`, error); + return null; + } + }); + ret = ret.filter((entry) => (entry !== null && entry.content)); + logger.debug(`Tool::ReadFiles Reading files in ${target} with pattern ${pattern} : ${ret.length} files`, ret.map((entry) => entry.path)); + return ret; + } + catch (error) { + logger.error('Error listing files', error); + throw error; + } + }, + parse: JSON.parse + } + }, + { + type: 'function', + function: { + name: 'remove_file', + description: 'Remove a file at given path', + parameters: { + type: 'object', + properties: { + path: { type: 'string' } + }, + required: ['path'] + }, + function: async (params) => { + try { + const filePath = path.join(target, sanitize(params.path)); + logger.debug(`Tool::RemoveFile Removing file ${filePath}`); + rm(filePath); + return true; + } + catch (error) { + logger.error('Error removing file', error); + throw error; + } + }, + parse: JSON.parse + } + }, + { + type: 'function', + function: { + name: 'rename_file', + description: 'Rename or move a file or directory', + parameters: { + type: 'object', + properties: { + src: { type: 'string' }, + dst: { type: 'string' } + }, + required: ['path'] + }, + function: async (params) => { + try { + const src = path.join(target, sanitize(params.src)); + const dst = path.join(target, sanitize(params.dst)); + logger.debug(`Tool::Rename file ${src} to ${dst}`); + rename(src, dst); + rm(src); + return true; + } + catch (error) { + logger.error('Error removing file', error); + throw error; + } + }, + parse: JSON.parse + } + }, + { + type: 'function', + function: { + name: "modify_project_files", + description: "Create or modify existing project files in one shot, preferably used for creating project structure)", + parameters: { + type: "object", + properties: { + files: { + type: "array", + items: { + type: "object", + properties: { + path: { type: "string" }, + content: { type: "string", description: "new file content (Part of JSON payload)" } + }, + required: ["path", "content"] + } + } + }, + required: ["files"], + }, + function: async (ret) => { + try { + if (!target) { + logger.error(`Tool::FS:modify_project_files : Root path required`); + return; + } + let { files } = ret; + if (isString(files)) { + try { + files = JSON.parse(files); + } + catch (error) { + logger.error(`Tool::modify_project_files : Structure Error parsing files`, error, ret); + // Consider writing the raw input for debugging if JSON parsing fails + // write(path.join(target, 'tools-output-error.json'), files) + return error.message; + } + } + for (const file of files) { + const sanitizedPath = sanitize(file.path); + const filePath = path.join(target, sanitizedPath); + logger.debug(`Tool:modify_project_files writing file ${filePath}`); + try { + // const contentToWrite = decodeContentSmart(file.content, logger, sanitizedPath); + try { + await write(filePath, file.content); + } + catch (writeError) { + logger.error(`Tool:modify_project_files Error writing file ${filePath}`, writeError); + } + } + catch (error) { + logger.error(`Tool:modify_project_files Error processing file content for ${filePath}`, error); + } + } + } + catch (error) { + logger.error(`Error creating project structure`, error); + } + }, + parse: JSON.parse, + }, + }, + { + type: 'function', + function: { + name: "write_file", + description: "Writes to a file, given a path and content (Part of JSON payload). No directory or file exists check needed!", + parameters: { + type: "object", + properties: { + file: { + type: "object", + properties: { + path: { type: "string" }, + content: { type: "string", description: "new file content (Part of JSON payload)" } + } + } + }, + required: ["file"], + }, + function: async (params) => { + let fileInfo; + try { + if (isString(params)) { + try { + params = JSON.parse(params); + } + catch (error) { + logger.error(`Tool::write_file : Structure Error parsing JSON`, error, params); + return error.message; + } + } + fileInfo = params.file; // Keep fileInfo accessible + if (!target || !fileInfo || !fileInfo.path || typeof fileInfo.content === 'undefined') { + logger.error(`Tool::write_file : Path/Target/Content are required`, fileInfo); + return false; // Indicate failure + } + const sanitizedPath = sanitize(fileInfo.path); + const filePath = path.join(target, sanitizedPath); + logger.debug(`Tool::write_file Writing file ${filePath}`); + try { + // Use the smart decoding helper function + // const contentToWrite = decodeContentSmart(fileInfo.content, logger, sanitizedPath); + await write(filePath, fileInfo.content); + return true; + } + catch (error) { + // Log error related to processing or writing the file + logger.error(`Tool:write_file Error processing or writing file ${sanitizedPath}`, error); + return false; // Indicate failure + } + } + catch (error) { + logger.error(`Tool:write_file Error writing file ${fileInfo?.path ? sanitize(fileInfo.path) : 'unknown'}`, error); + return false; // Indicate failure + } + }, + parse: JSON.parse, + }, + }, + { + type: 'function', + function: { + name: "file_exists", + description: "check if a file or folder exists", + parameters: { + type: "object", + properties: { + file: { + type: "object", + properties: { + path: { type: "string" } + } + } + }, + required: ["file"], + }, + function: async (ret) => { + try { + if (isString(ret)) { + try { + ret = JSON.parse(ret); + } + catch (error) { + logger.error(`Tool::file_exists : Structure Error parsing files`, error, ret); + return error.message; + } + } + const { file } = ret; + if (!target || !file.path) { + logger.error(`Tool::file_exists : Path is required`, ret); + return; + } + const sanitizedPath = sanitize(file.path); + const filePath = path.join(target, sanitizedPath); + const res = exists(filePath); + logger.debug(`Tool::file_exists ${filePath} exists: ${res}`); + return res ? true : false; + } + catch (error) { + logger.error(`Tool:file_exists error`, error); + return false; + } + }, + parse: JSON.parse, + }, + }, + { + type: 'function', + function: { + name: "read_file", + description: "read a file, at given a path", + parameters: { + type: "object", + properties: { + file: { + type: "object", + properties: { + path: { type: "string" } + } + } + }, + required: ["file"], + }, + function: async (ret) => { + try { + const { file } = ret; + const sanitizedPath = sanitize(file.path); + const filePath = path.join(target, sanitizedPath); + logger.debug(`Tool::ReadFile Reading file ${filePath}`); + return read(filePath, 'string'); + } + catch (error) { + logger.error(`Error reading file`, error); + } + }, + parse: JSON.parse + } + } + ]; +}; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZnMgY29weS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9saWIvdG9vbHMvZnMgY29weS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssSUFBSSxNQUFNLE1BQU0sQ0FBQTtBQUU1QixPQUFPLEVBQUUsSUFBSSxJQUFJLEVBQUUsRUFBRSxNQUFNLHFCQUFxQixDQUFBO0FBQ2hELE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQTtBQUNwRCxPQUFPLEVBQUUsSUFBSSxJQUFJLEtBQUssRUFBRSxNQUFNLG9CQUFvQixDQUFBO0FBQ2xELE9BQU8sRUFBRSxJQUFJLElBQUksSUFBSSxFQUFFLE1BQU0sbUJBQW1CLENBQUE7QUFDaEQsT0FBTyxFQUFFLElBQUksSUFBSSxNQUFNLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQTtBQUNwRCxPQUFPLEVBQUUsSUFBSSxJQUFJLE1BQU0sRUFBRSxNQUFNLHFCQUFxQixDQUFBO0FBQ3BELE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQTtBQUM3QyxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sbUJBQW1CLENBQUE7QUFFM0MsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGdCQUFnQixDQUFBO0FBRTNDLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQTtBQUVqRCxPQUFPLEVBQUUsSUFBSSxFQUFFLE1BQU0sTUFBTSxDQUFBO0FBRTNCLE1BQU0sUUFBUSxHQUFHLENBQUMsR0FBVyxFQUFXLEVBQUU7SUFDdEMsbURBQW1EO0lBQ25ELHVDQUF1QztJQUN2QyxpRkFBaUY7SUFDakYsSUFBSSxDQUFDLEdBQUcsSUFBSSxHQUFHLENBQUMsTUFBTSxHQUFHLENBQUMsS0FBSyxDQUFDLEVBQUU7UUFDaEMsT0FBTyxLQUFLLENBQUM7S0FDZDtJQUVELE1BQU0sV0FBVyxHQUFHLHdCQUF3QixDQUFDO0lBQzdDLElBQUksQ0FBQyxXQUFX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 \ No newline at end of file diff --git a/packages/ai-tools/dist/lib/tools/fs.js b/packages/ai-tools/dist/lib/tools/fs.js index fd4c8d19..ab5bf53f 100644 --- a/packages/ai-tools/dist/lib/tools/fs.js +++ b/packages/ai-tools/dist/lib/tools/fs.js @@ -84,7 +84,6 @@ const decodeContentSmart = (content, logger, identifier) => { }; export const tools = (target, options) => { const logger = toolLogger('fs', options); - const category = 'fs'; return [ { type: 'function', @@ -430,4 +429,4 @@ export const tools = (target, options) => { } ]; }; -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZnMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvbGliL3Rvb2xzL2ZzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxJQUFJLE1BQU0sTUFBTSxDQUFBO0FBRTVCLE9BQU8sRUFBRSxJQUFJLElBQUksRUFBRSxFQUFFLE1BQU0scUJBQXFCLENBQUE7QUFDaEQsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLDJCQUEyQixDQUFBO0FBQ3BELE9BQU8sRUFBRSxJQUFJLElBQUksS0FBSyxFQUFFLE1BQU0sb0JBQW9CLENBQUE7QUFDbEQsT0FBTyxFQUFFLElBQUksSUFBSSxJQUFJLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQTtBQUNoRCxPQUFPLEVBQUUsSUFBSSxJQUFJLE1BQU0sRUFBRSxNQUFNLHFCQUFxQixDQUFBO0FBQ3BELE9BQU8sRUFBRSxJQUFJLElBQUksTUFBTSxFQUFFLE1BQU0scUJBQXFCLENBQUE7QUFDcEQsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLG9CQUFvQixDQUFBO0FBQzdDLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQTtBQUUzQyxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sZ0JBQWdCLENBQUE7QUFFM0MsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLG9CQUFvQixDQUFBO0FBRWpELE9BQU8sRUFBRSxJQUFJLEVBQUUsTUFBTSxNQUFNLENBQUE7QUFFM0IsTUFBTSxRQUFRLEdBQUcsQ0FBQyxHQUFXLEVBQVcsRUFBRTtJQUN0QyxtREFBbUQ7SUFDbkQsdUNBQXVDO0lBQ3ZDLGlGQUFpRjtJQUNqRixJQUFJLENBQUMsR0FBRyxJQUFJLEdBQUcsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxLQUFLLENBQUMsRUFBRTtRQUNoQyxPQUFPLEtBQUssQ0FBQztLQUNkO0lBRUQsTUFBTSxXQUFXLEdBQUcsd0JBQXdCLENBQUM7SUFDN0MsSUFBSSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUU7UUFDMUIsT0FBTyxLQUFLLENBQUM7S0FDZDtJQUVELG1EQUFtRDtJQUNuRCxJQUFJO1FBQ0YsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUcscUJBQXFCO1FBQ2xELE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLHNCQUFzQjtRQUV2RCw0Q0FBNEM7UUFDNUMsT0FBTyxTQUFTLEtBQUssR0FBRyxDQUFDO0tBQzFCO0lBQUMsTUFBTTtRQUNOLE9BQU8sS0FBSyxDQUFDO0tBQ2Q7QUFDSCxDQUFDLENBQUE7QUFFSCxNQUFNLENBQUMsTUFBTSxhQUFhLEdBQUcsQ0FBQyxNQUFjLEVBQVUsRUFBRTtJQUNwRCxJQUFJO1FBQ0EsSUFBRyxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUMsRUFBRTtZQUNsQixPQUFPLE1BQU0sQ0FBQTtTQUNoQjtRQUNELE9BQU8sTUFBTSxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsUUFBUSxDQUFDLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxDQUFDO0tBQzFEO0lBQUMsT0FBTyxLQUFLLEVBQUU7UUFDWixNQUFNLElBQUksS0FBSyxDQUFDLGdDQUFnQyxDQUFDLENBQUM7S0FDckQ7QUFDTCxDQUFDLENBQUM7QUFFRiw0Q0FBNEM7QUFDNUMsTUFBTSxrQkFBa0IsR0FBRyxDQUFDLE9BQWUsRUFBRSxNQUFXLEVBQUUsVUFBa0IsRUFBVSxFQUFFO0lBQ3BGLElBQUksQ0FBQyxPQUFPLElBQUksT0FBTyxPQUFPLEtBQUssUUFBUSxFQUFFO1FBQ3pDLE9BQU8sT0FBTyxDQUFDLENBQUMsOERBQThEO0tBQ2pGO0lBRUQsTUFBTSxLQUFLLEdBQUcsT0FBTyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUNyQyxNQUFNLGNBQWMsR0FBRyxLQUFLLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxFQUFFO1FBQ3BDLE1BQU0sV0FBVyxHQUFHLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQztRQUNoQyxJQUFJLENBQUMsV0FBVyxFQUFFO1lBQ2QsT0FBTyxFQUFFLENBQUMsQ0FBQyxpRkFBaUY7U0FDL0Y7UUFFRCxJQUFJO1lBQ0EsMkJBQTJCO1lBQzNCLE1BQU0sV0FBVyxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsV0FBVyxFQUFFLFFBQVEsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsQ0FBQztZQUN6RSxvREFBb0Q7WUFDcEQsTUFBTSxhQUFhLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQyxXQUFXLEVBQUUsT0FBTyxDQUFDLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1lBRTNFLDRCQUE0QjtZQUM1QixzREFBc0Q7WUFDdEQseUZBQXlGO1lBQ3pGLE1BQU0sYUFBYSxHQUFHLFdBQVcsQ0FBQyxPQUFPLENBQUMsU0FBUyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1lBQ3pELE1BQU0sY0FBYyxHQUFHLGFBQWEsQ0FBQyxPQUFPLENBQUMsU0FBUyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1lBRTVELElBQUksYUFBYSxLQUFLLFdBQVcsSUFBSSxjQUFjLEtBQUssYUFBYSxFQUFFO2dCQUNuRSxNQUFNLENBQUMsS0FBSyxDQUFDLHdDQUF3QyxVQUFVLEVBQUUsQ0FBQyxDQUFDO2dCQUNuRSxPQUFPLFdBQVcsQ0FBQzthQUN0QjtZQUNELDJDQUEyQztZQUMzQyxNQUFNLENBQUMsS0FBSyxDQUFDLDRCQUE0QixVQUFVLGdCQUFnQixXQUFXLG1CQUFtQixhQUFhLGlDQUFpQyxDQUFDLENBQUM7WUFDakosT0FBTyxXQUFXLENBQUM7U0FDdEI7UUFBQyxPQUFPLFdBQVcsRUFBRTtZQUNsQixzREFBc0Q7WUFDdEQsMkRBQTJEO1lBQzNELE1BQU0sQ0FBQyxLQUFLLENBQUMsc0NBQXNDLFVBQVUsZ0NBQWdDLFdBQVcsRUFBRSxDQUFDLENBQUM7WUFDNUcsT0FBTyxXQUFXLENBQUMsQ0FBQywrQkFBK0I7U0FDdEQ7SUFDTCxDQUFDLENBQUMsQ0FBQztJQUdILHlDQUF5QztJQUN6QyxPQUFPLGNBQWMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7QUFDckMsQ0FBQyxDQUFDO0FBRUYsTUFBTSxDQUFDLE1BQU0sS0FBSyxHQUFHLENBQUMsTUFBYyxFQUFFLE9BQWtCLEVBQWMsRUFBRTtJQUNwRSxNQUFNLE1BQU0sR0FBRyxVQUFVLENBQUMsSUFBSSxFQUFFLE9BQU8sQ0FBQyxDQUFBO0lBQ3hDLE1BQU0sUUFBUSxHQUFHLElBQUksQ0FBQTtJQUNyQixPQUFPO1FBQ0g7WUFDSSxJQUFJLEVBQUUsVUFBVTtZQUNoQixRQUFRLEVBQUU7Z0JBQ04sSUFBSSxFQUFFLFlBQVk7Z0JBQ2xCLFdBQVcsRUFBRSwrQkFBK0I7Z0JBQzVDLFVBQVUsRUFBRTtvQkFDUixJQUFJLEVBQUUsUUFBUTtvQkFDZCxVQUFVLEVBQUU7d0JBQ1IsU0FBUyxFQUFFLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRTt3QkFDN0IsT0FBTyxFQUFFLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRSxRQUFRLEVBQUUsSUFBSSxFQUFFO3FCQUM5QztvQkFDRCxRQUFRLEVBQUUsQ0FBQyxXQUFXLENBQUM7aUJBQzFCO2dCQUNELFFBQVEsRUFBRSxLQUFLLEVBQUUsTUFBVyxFQUFFLEVBQUU7b0JBQzVCLElBQUk7d0JBQ0EsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsUUFBUSxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDO3dCQUNoRSxJQUFJLENBQUMsTUFBTSxDQUFDLFNBQVMsQ0FBQyxFQUFFOzRCQUNwQixNQUFNLENBQUMsS0FBSyxDQUFDLDZCQUE2QixTQUFTLGlCQUFpQixDQUFDLENBQUM7NEJBQ3RFLE9BQU8sRUFBRSxDQUFBO3lCQUNaO3dCQUNELElBQUksT0FBTyxHQUFHLE1BQU0sQ0FBQyxPQUFPLElBQUksTUFBTSxDQUFDO3dCQUN2QyxNQUFNLENBQUMsS0FBSyxDQUFDLG9DQUFvQyxTQUFTLGlCQUFpQixPQUFPLEVBQUUsQ0FBQyxDQUFDO3dCQUN0RixPQUFPLEdBQUc7NEJBQ04sR0FBRyxZQUFZOzRCQUNmLE9BQU87eUJBQ1YsQ0FBQTt3QkFDRCxNQUFNLEdBQUcsR0FBRyxNQUFNLElBQUksQ0FBQyxPQUFPLEVBQUU7NEJBQzVCLEdBQUcsRUFBRSxTQUFTOzRCQUNkLFFBQVEsRUFBRSxLQUFLOzRCQUNmLE1BQU0sRUFBRSxZQUFZO3lCQUN2QixDQUFDLENBQUM7d0JBQ0gsT0FBTyxHQUFHLENBQUE7cUJBQ2I7b0JBQUMsT0FBTyxLQUFLLEVBQUU7d0JBQ1osTUFBTSxDQUFDLEtBQUssQ0FBQyxxQkFBcUIsRUFBRSxLQUFLLENBQUMsQ0FBQzt3QkFDM0MsTUFBTSxLQUFLLENBQUM7cUJBQ2Y7Z0JBQ0wsQ0FBQztnQkFDRCxLQUFLLEVBQUUsSUFBSSxDQUFDLEtBQUs7YUFDcEI7U0FDeUI7UUFDOUI7WUFDSSxJQUFJLEVBQUUsVUFBVTtZQUNoQixRQUFRLEVBQUU7Z0JBQ04sSUFBSSxFQUFFLFlBQVk7Z0JBQ2xCLFdBQVcsRUFBRSxpREFBaUQ7Z0JBQzlELFVBQVUsRUFBRTtvQkFDUixJQUFJLEVBQUUsUUFBUTtvQkFDZCxVQUFVLEVBQUU7d0JBQ1IsU0FBUyxFQUFFLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRTt3QkFDN0IsT0FBTyxFQUFFLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRSxRQUFRLEVBQUUsSUFBSSxFQUFFO3FCQUM5QztvQkFDRCxRQUFRLEVBQUUsQ0FBQyxXQUFXLENBQUM7aUJBQzFCO2dCQUNELFFBQVEsRUFBRSxLQUFLLEVBQUUsTUFBVyxFQUFFLEVBQUU7b0JBQzVCLElBQUk7d0JBQ0EsTUFBTSxPQUFPLEdBQUcsTUFBTSxDQUFDLE9BQU8sSUFBSSxNQUFNLENBQUM7d0JBQ3pDLElBQUksT0FBTyxHQUFHLE9BQU8sQ0FBQyxNQUFNLEVBQUUsT0FBTyxDQUFDLENBQUM7d0JBQ3ZDLElBQUksR0FBRyxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQyxLQUFLLEVBQUUsRUFBRTs0QkFDNUIsSUFBSTtnQ0FDQSxJQUFJLE9BQU8sR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7Z0NBQzFCLE9BQU87b0NBQ0gsSUFBSSxFQUFFLElBQUksQ0FBQyxRQUFRLENBQUMsTUFBTSxFQUFFLEtBQUssQ0FBQyxDQUFDLE9BQU8sQ0FBQyxLQUFLLEVBQUUsR0FBRyxDQUFDO29DQUN0RCxPQUFPLEVBQUUsT0FBTyxDQUFDLFFBQVEsRUFBRTtpQ0FDOUIsQ0FBQTs2QkFDSjs0QkFBQyxPQUFPLEtBQUssRUFBRTtnQ0FDWixNQUFNLENBQUMsS0FBSyxDQUFDLHNCQUFzQixLQUFLLEdBQUcsRUFBRSxLQUFLLENBQUMsQ0FBQTtnQ0FDbkQsT0FBTyxJQUFJLENBQUE7NkJBQ2Q7d0JBQ0wsQ0FBQyxDQUFDLENBQUE7d0JBQ0YsR0FBRyxHQUFHLEdBQUcsQ0FBQyxNQUFNLENBQUMsQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLENBQUMsS0FBSyxLQUFLLElBQUksSUFBSSxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQTt3QkFDOUQsTUFBTSxDQUFDLEtBQUssQ0FBQyxvQ0FBb0MsTUFBTSxpQkFBaUIsT0FBTyxNQUFNLEdBQUcsQ0FBQyxNQUFNLFFBQVEsRUFBRSxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQzt3QkFDekksT0FBTyxHQUFHLENBQUE7cUJBQ2I7b0JBQUMsT0FBTyxLQUFLLEVBQUU7d0JBQ1osTUFBTSxDQUFDLEtBQUssQ0FBQyxxQkFBcUIsRUFBRSxLQUFLLENBQUMsQ0FBQzt3QkFDM0MsTUFBTSxLQUFLLENBQUM7cUJBQ2Y7Z0JBQ0wsQ0FBQztnQkFDRCxLQUFLLEVBQUUsSUFBSSxDQUFDLEtBQUs7YUFDcEI7U0FDeUI7UUFDOUI7WUFDSSxJQUFJLEVBQUUsVUFBVTtZQUNoQixRQUFRLEVBQUU7Z0JBQ04sSUFBSSxFQUFFLGFBQWE7Z0JBQ25CLFdBQVcsRUFBRSw2QkFBNkI7Z0JBQzFDLFVBQVUsRUFBRTtvQkFDUixJQUFJLEVBQUUsUUFBUTtvQkFDZCxVQUFVLEVBQUU7d0JBQ1IsSUFBSSxFQUFFLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRTtxQkFDM0I7b0JBQ0QsUUFBUSxFQUFFLENBQUMsTUFBTSxDQUFDO2lCQUNyQjtnQkFDRCxRQUFRLEVBQUUsS0FBSyxFQUFFLE1BQVcsRUFBRSxFQUFFO29CQUM1QixJQUFJO3dCQUNBLE1BQU0sUUFBUSxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLFFBQVEsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQzt3QkFDMUQsTUFBTSxDQUFDLEtBQUssQ0FBQyxrQ0FBa0MsUUFBUSxFQUFFLENBQUMsQ0FBQzt3QkFDM0QsRUFBRSxDQUFDLFFBQVEsQ0FBQyxDQUFDO3dCQUNiLE9BQU8sSUFBSSxDQUFDO3FCQUNmO29CQUFDLE9BQU8sS0FBSyxFQUFFO3dCQUNaLE1BQU0sQ0FBQyxLQUFLLENBQUMscUJBQXFCLEVBQUUsS0FBSyxDQUFDLENBQUM7d0JBQzNDLE1BQU0sS0FBSyxDQUFDO3FCQUNmO2dCQUNMLENBQUM7Z0JBQ0QsS0FBSyxFQUFFLElBQUksQ0FBQyxLQUFLO2FBQ3BCO1NBQ3lCO1FBQzlCO1lBQ0ksSUFBSSxFQUFFLFVBQVU7WUFDaEIsUUFBUSxFQUFFO2dCQUNOLElBQUksRUFBRSxhQUFhO2dCQUNuQixXQUFXLEVBQUUsb0NBQW9DO2dCQUNqRCxVQUFVLEVBQUU7b0JBQ1IsSUFBSSxFQUFFLFFBQVE7b0JBQ2QsVUFBVSxFQUFFO3dCQUNSLEdBQUcsRUFBRSxFQUFFLElBQUksRUFBRSxRQUFRLEVBQUU7d0JBQ3ZCLEdBQUcsRUFBRSxFQUFFLElBQUksRUFBRSxRQUFRLEVBQUU7cUJBQzFCO29CQUNELFFBQVEsRUFBRSxDQUFDLE1BQU0sQ0FBQztpQkFDckI7Z0JBQ0QsUUFBUSxFQUFFLEtBQUssRUFBRSxNQUFXLEVBQUUsRUFBRTtvQkFDNUIsSUFBSTt3QkFDQSxNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRSxRQUFRLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUE7d0JBQ25ELE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLFFBQVEsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQTt3QkFDbkQsTUFBTSxDQUFDLEtBQUssQ0FBQyxxQkFBcUIsR0FBRyxPQUFPLEdBQUcsRUFBRSxDQUFDLENBQUE7d0JBQ2xELE1BQU0sQ0FBQyxHQUFHLEVBQUUsR0FBRyxDQUFDLENBQUE7d0JBQ2hCLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQTt3QkFDUCxPQUFPLElBQUksQ0FBQTtxQkFDZDtvQkFBQyxPQUFPLEtBQUssRUFBRTt3QkFDWixNQUFNLENBQUMsS0FBSyxDQUFDLHFCQUFxQixFQUFFLEtBQUssQ0FBQyxDQUFBO3dCQUMxQyxNQUFNLEtBQUssQ0FBQTtxQkFDZDtnQkFDTCxDQUFDO2dCQUNELEtBQUssRUFBRSxJQUFJLENBQUMsS0FBSzthQUNwQjtTQUN5QjtRQUM5QjtZQUNJLElBQUksRUFBRSxVQUFVO1lBQ2hCLFFBQVEsRUFBRTtnQkFDTixJQUFJLEVBQUUsc0JBQXNCO2dCQUM1QixXQUFXLEVBQUUsc0dBQXNHO2dCQUNuSCxVQUFVLEVBQUU7b0JBQ1IsSUFBSSxFQUFFLFFBQVE7b0JBQ2QsVUFBVSxFQUFFO3dCQUNSLEtBQUssRUFBRTs0QkFDSCxJQUFJLEVBQUUsT0FBTzs0QkFDYixLQUFLLEVBQUU7Z0NBQ0gsSUFBSSxFQUFFLFFBQVE7Z0NBQ2QsVUFBVSxFQUFFO29DQUNSLElBQUksRUFBRSxFQUFFLElBQUksRUFBRSxRQUFRLEVBQUU7b0NBQ3hCLE9BQU8sRUFBRSxFQUFFLElBQUksRUFBRSxRQUFRLEVBQUUsV0FBVyxFQUFFLHlDQUF5QyxFQUFFO2lDQUN0RjtnQ0FDRCxRQUFRLEVBQUUsQ0FBQyxNQUFNLEVBQUUsU0FBUyxDQUFDOzZCQUNoQzt5QkFDSjtxQkFDSjtvQkFDRCxRQUFRLEVBQUUsQ0FBQyxPQUFPLENBQUM7aUJBQ3RCO2dCQUNELFFBQVEsRUFBRSxLQUFLLEVBQUUsR0FBRyxFQUFFLEVBQUU7b0JBQ3BCLElBQUk7d0JBQ0EsSUFBSSxDQUFDLE1BQU0sRUFBRTs0QkFDVCxNQUFNLENBQUMsS0FBSyxDQUFDLG9EQUFvRCxDQUFDLENBQUE7NEJBQ2xFLE9BQU07eUJBQ1Q7d0JBQ0QsSUFBSSxFQUFFLEtBQUssRUFBRSxHQUFHLEdBQVUsQ0FBQTt3QkFDMUIsSUFBSSxRQUFRLENBQUMsS0FBSyxDQUFDLEVBQUU7NEJBQ2pCLElBQUk7Z0NBQ0EsS0FBSyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLENBQUE7NkJBQzVCOzRCQUFDLE9BQU8sS0FBVSxFQUFFO2dDQUNqQixNQUFNLENBQUMsS0FBSyxDQUFDLDREQUE0RCxFQUFFLEtBQUssRUFBRSxHQUFHLENBQUMsQ0FBQTtnQ0FDdEYscUVBQXFFO2dDQUNyRSw4REFBOEQ7Z0NBQzlELE9BQU8sS0FBSyxDQUFDLE9BQU8sQ0FBQTs2QkFDdkI7eUJBQ0o7d0JBQ0QsS0FBSyxNQUFNLElBQUksSUFBSSxLQUFLLEVBQUU7NEJBQ3RCLE1BQU0sYUFBYSxHQUFHLFFBQVEsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7NEJBQzFDLE1BQU0sUUFBUSxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLGFBQWEsQ0FBQyxDQUFDOzRCQUNsRCxNQUFNLENBQUMsS0FBSyxDQUFDLDBDQUEwQyxRQUFRLEVBQUUsQ0FBQyxDQUFBOzRCQUNsRSxJQUFJO2dDQUNBLGtGQUFrRjtnQ0FDbEYsSUFBSTtvQ0FDQSxNQUFNLEtBQUssQ0FBQyxRQUFRLEVBQUUsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFBO2lDQUN0QztnQ0FBQyxPQUFPLFVBQVUsRUFBRTtvQ0FDakIsTUFBTSxDQUFDLEtBQUssQ0FBQyxnREFBZ0QsUUFBUSxFQUFFLEVBQUUsVUFBVSxDQUFDLENBQUE7aUNBQ3ZGOzZCQUNKOzRCQUFDLE9BQU8sS0FBSyxFQUFFO2dDQUNaLE1BQU0sQ0FBQyxLQUFLLENBQUMsK0RBQStELFFBQVEsRUFBRSxFQUFFLEtBQUssQ0FBQyxDQUFBOzZCQUNqRzt5QkFDSjtxQkFDSjtvQkFBQyxPQUFPLEtBQUssRUFBRTt3QkFDWixNQUFNLENBQUMsS0FBSyxDQUFDLGtDQUFrQyxFQUFFLEtBQUssQ0FBQyxDQUFBO3FCQUMxRDtnQkFDTCxDQUFDO2dCQUVELEtBQUssRUFBRSxJQUFJLENBQUMsS0FBSzthQUNwQjtTQUNvQztRQUN6QztZQUNJLElBQUksRUFBRSxVQUFVO1lBQ2hCLFFBQVEsRUFBRTtnQkFDTixJQUFJLEVBQUUsWUFBWTtnQkFDbEIsV0FBVyxFQUFFLDhHQUE4RztnQkFDM0gsVUFBVSxFQUFFO29CQUNSLElBQUksRUFBRSxRQUFRO29CQUNkLFVBQVUsRUFBRTt3QkFDUixJQUFJLEVBQUU7NEJBQ0YsSUFBSSxFQUFFLFFBQVE7NEJBQ2QsVUFBVSxFQUFFO2dDQUNSLElBQUksRUFBRSxFQUFFLElBQUksRUFBRSxRQUFRLEVBQUU7Z0NBQ3hCLE9BQU8sRUFBRSxFQUFFLElBQUksRUFBRSxRQUFRLEVBQUUsV0FBVyxFQUFFLHlDQUF5QyxFQUFFOzZCQUN0Rjt5QkFDSjtxQkFDSjtvQkFDRCxRQUFRLEVBQUUsQ0FBQyxNQUFNLENBQUM7aUJBQ3JCO2dCQUNELFFBQVEsRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLEVBQUU7b0JBQ3ZCLElBQUksUUFBUSxDQUFDO29CQUNiLElBQUk7d0JBQ0EsSUFBSSxRQUFRLENBQUMsTUFBTSxDQUFDLEVBQUU7NEJBQ2xCLElBQUk7Z0NBQ0EsTUFBTSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLENBQUE7NkJBQzlCOzRCQUFDLE9BQU8sS0FBVSxFQUFFO2dDQUNqQixNQUFNLENBQUMsS0FBSyxDQUFDLGlEQUFpRCxFQUFFLEtBQUssRUFBRSxNQUFNLENBQUMsQ0FBQTtnQ0FDOUUsT0FBTyxLQUFLLENBQUMsT0FBTyxDQUFBOzZCQUN2Qjt5QkFDSjt3QkFFRCxRQUFRLEdBQUksTUFBYyxDQUFDLElBQUksQ0FBQyxDQUFDLDJCQUEyQjt3QkFFNUQsSUFBSSxDQUFDLE1BQU0sSUFBSSxDQUFDLFFBQVEsSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLElBQUksT0FBTyxRQUFRLENBQUMsT0FBTyxLQUFLLFdBQVcsRUFBRTs0QkFDbkYsTUFBTSxDQUFDLEtBQUssQ0FBQyxxREFBcUQsRUFBRSxRQUFRLENBQUMsQ0FBQTs0QkFDN0UsT0FBTyxLQUFLLENBQUMsQ0FBQyxtQkFBbUI7eUJBQ3BDO3dCQUVELE1BQU0sYUFBYSxHQUFHLFFBQVEsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLENBQUM7d0JBQzlDLE1BQU0sUUFBUSxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLGFBQWEsQ0FBQyxDQUFBO3dCQUNqRCxNQUFNLENBQUMsS0FBSyxDQUFDLGlDQUFpQyxRQUFRLEVBQUUsQ0FBQyxDQUFBO3dCQUN6RCxJQUFJOzRCQUNBLHlDQUF5Qzs0QkFDekMsc0ZBQXNGOzRCQUN0RixNQUFNLEtBQUssQ0FBQyxRQUFRLEVBQUUsUUFBUSxDQUFDLE9BQU8sQ0FBQyxDQUFBOzRCQUN2QyxPQUFPLElBQUksQ0FBQTt5QkFDZDt3QkFBQyxPQUFPLEtBQUssRUFBRTs0QkFDWixzREFBc0Q7NEJBQ3RELE1BQU0sQ0FBQyxLQUFLLENBQUMsb0RBQW9ELGFBQWEsRUFBRSxFQUFFLEtBQUssQ0FBQyxDQUFBOzRCQUN4RixPQUFPLEtBQUssQ0FBQSxDQUFDLG1CQUFtQjt5QkFDbkM7cUJBQ0o7b0JBQUMsT0FBTyxLQUFLLEVBQUU7d0JBQ1osTUFBTSxDQUFDLEtBQUssQ0FBQyxzQ0FBc0MsUUFBUSxFQUFFLElBQUksQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsU0FBUyxFQUFFLEVBQUUsS0FBSyxDQUFDLENBQUE7d0JBQ2pILE9BQU8sS0FBSyxDQUFBLENBQUMsbUJBQW1CO3FCQUNuQztnQkFDTCxDQUFDO2dCQUNELEtBQUssRUFBRSxJQUFJLENBQUMsS0FBSzthQUNwQjtTQUNvQztRQUN6QztZQUNJLElBQUksRUFBRSxVQUFVO1lBQ2hCLFFBQVEsRUFBRTtnQkFDTixJQUFJLEVBQUUsYUFBYTtnQkFDbkIsV0FBVyxFQUFFLGtDQUFrQztnQkFDL0MsVUFBVSxFQUFFO29CQUNSLElBQUksRUFBRSxRQUFRO29CQUNkLFVBQVUsRUFBRTt3QkFDUixJQUFJLEVBQUU7NEJBQ0YsSUFBSSxFQUFFLFFBQVE7NEJBQ2QsVUFBVSxFQUFFO2dDQUNSLElBQUksRUFBRSxFQUFFLElBQUksRUFBRSxRQUFRLEVBQUU7NkJBQzNCO3lCQUNKO3FCQUNKO29CQUNELFFBQVEsRUFBRSxDQUFDLE1BQU0sQ0FBQztpQkFDckI7Z0JBQ0QsUUFBUSxFQUFFLEtBQUssRUFBRSxHQUFHLEVBQUUsRUFBRTtvQkFDcEIsSUFBSTt3QkFDQSxJQUFJLFFBQVEsQ0FBQyxHQUFHLENBQUMsRUFBRTs0QkFDZixJQUFJO2dDQUNBLEdBQUcsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFBOzZCQUN4Qjs0QkFBQyxPQUFPLEtBQVUsRUFBRTtnQ0FDakIsTUFBTSxDQUFDLEtBQUssQ0FBQyxtREFBbUQsRUFBRSxLQUFLLEVBQUUsR0FBRyxDQUFDLENBQUE7Z0NBQzdFLE9BQU8sS0FBSyxDQUFDLE9BQU8sQ0FBQTs2QkFDdkI7eUJBQ0o7d0JBQ0QsTUFBTSxFQUFFLElBQUksRUFBRSxHQUFHLEdBQVUsQ0FBQTt3QkFDM0IsSUFBSSxDQUFDLE1BQU0sSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUU7NEJBQ3ZCLE1BQU0sQ0FBQyxLQUFLLENBQUMsc0NBQXNDLEVBQUUsR0FBRyxDQUFDLENBQUE7NEJBQ3pELE9BQU07eUJBQ1Q7d0JBQ0QsTUFBTSxhQUFhLEdBQUcsUUFBUSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQzt3QkFDMUMsTUFBTSxRQUFRLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsYUFBYSxDQUFDLENBQUE7d0JBQ2pELE1BQU0sR0FBRyxHQUFHLE1BQU0sQ0FBQyxRQUFRLENBQUMsQ0FBQTt3QkFDNUIsTUFBTSxDQUFDLEtBQUssQ0FBQyxxQkFBcUIsUUFBUSxZQUFZLEdBQUcsRUFBRSxDQUFDLENBQUE7d0JBQzVELE9BQU8sR0FBRyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQTtxQkFDNUI7b0JBQUMsT0FBTyxLQUFLLEVBQUU7d0JBQ1osTUFBTSxDQUFDLEtBQUssQ0FBQyx3QkFBd0IsRUFBRSxLQUFLLENBQUMsQ0FBQTt3QkFDN0MsT0FBTyxLQUFLLENBQUE7cUJBQ2Y7Z0JBQ0wsQ0FBQztnQkFDRCxLQUFLLEVBQUUsSUFBSSxDQUFDLEtBQUs7YUFDcEI7U0FDb0M7UUFDekM7WUFDSSxJQUFJLEVBQUUsVUFBVTtZQUNoQixRQUFRLEVBQUU7Z0JBQ04sSUFBSSxFQUFFLFdBQVc7Z0JBQ2pCLFdBQVcsRUFBRSw4QkFBOEI7Z0JBQzNDLFVBQVUsRUFBRTtvQkFDUixJQUFJLEVBQUUsUUFBUTtvQkFDZCxVQUFVLEVBQUU7d0JBQ1IsSUFBSSxFQUFFOzRCQUNGLElBQUksRUFBRSxRQUFROzRCQUNkLFVBQVUsRUFBRTtnQ0FDUixJQUFJLEVBQUUsRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFOzZCQUMzQjt5QkFDSjtxQkFDSjtvQkFDRCxRQUFRLEVBQUUsQ0FBQyxNQUFNLENBQUM7aUJBQ3JCO2dCQUNELFFBQVEsRUFBRSxLQUFLLEVBQUUsR0FBRyxFQUFFLEVBQUU7b0JBQ3BCLElBQUk7d0JBQ0EsTUFBTSxFQUFFLElBQUksRUFBRSxHQUFHLEdBQVUsQ0FBQTt3QkFDM0IsTUFBTSxhQUFhLEdBQUcsUUFBUSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQzt3QkFDMUMsTUFBTSxRQUFRLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsYUFBYSxDQUFDLENBQUE7d0JBQ2pELE1BQU0sQ0FBQyxLQUFLLENBQUMsK0JBQStCLFFBQVEsRUFBRSxDQUFDLENBQUE7d0JBQ3ZELE9BQU8sSUFBSSxDQUFDLFFBQVEsRUFBRSxRQUFRLENBQUMsQ0FBQTtxQkFDbEM7b0JBQUMsT0FBTyxLQUFLLEVBQUU7d0JBQ1osTUFBTSxDQUFDLEtBQUssQ0FBQyxvQkFBb0IsRUFBRSxLQUFLLENBQUMsQ0FBQTtxQkFDNUM7Z0JBQ0wsQ0FBQztnQkFDRCxLQUFLLEVBQUUsSUFBSSxDQUFDLEtBQUs7YUFDcEI7U0FDb0M7S0FDNUMsQ0FBQTtBQUNMLENBQUMsQ0FBQyJ9 \ No newline at end of file +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZnMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvbGliL3Rvb2xzL2ZzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxJQUFJLE1BQU0sTUFBTSxDQUFBO0FBRTVCLE9BQU8sRUFBRSxJQUFJLElBQUksRUFBRSxFQUFFLE1BQU0scUJBQXFCLENBQUE7QUFDaEQsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLDJCQUEyQixDQUFBO0FBQ3BELE9BQU8sRUFBRSxJQUFJLElBQUksS0FBSyxFQUFFLE1BQU0sb0JBQW9CLENBQUE7QUFDbEQsT0FBTyxFQUFFLElBQUksSUFBSSxJQUFJLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQTtBQUNoRCxPQUFPLEVBQUUsSUFBSSxJQUFJLE1BQU0sRUFBRSxNQUFNLHFCQUFxQixDQUFBO0FBQ3BELE9BQU8sRUFBRSxJQUFJLElBQUksTUFBTSxFQUFFLE1BQU0scUJBQXFCLENBQUE7QUFDcEQsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLG9CQUFvQixDQUFBO0FBQzdDLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQTtBQUUzQyxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sZ0JBQWdCLENBQUE7QUFFM0MsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLG9CQUFvQixDQUFBO0FBRWpELE9BQU8sRUFBRSxJQUFJLEVBQUUsTUFBTSxNQUFNLENBQUE7QUFFM0IsTUFBTSxRQUFRLEdBQUcsQ0FBQyxHQUFXLEVBQVcsRUFBRTtJQUN0QyxtREFBbUQ7SUFDbkQsdUNBQXVDO0lBQ3ZDLGlGQUFpRjtJQUNqRixJQUFJLENBQUMsR0FBRyxJQUFJLEdBQUcsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxLQUFLLENBQUMsRUFBRTtRQUNoQyxPQUFPLEtBQUssQ0FBQztLQUNkO0lBRUQsTUFBTSxXQUFXLEdBQUcsd0JBQXdCLENBQUM7SUFDN0MsSUFBSSxDQUFDLFdBQVcsQ0FBQyxJQUFJ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 \ No newline at end of file diff --git a/packages/ai-tools/dist/lib/tools/keyv.d.ts b/packages/ai-tools/dist/lib/tools/keyv.d.ts new file mode 100644 index 00000000..141cfa14 --- /dev/null +++ b/packages/ai-tools/dist/lib/tools/keyv.d.ts @@ -0,0 +1,5 @@ +import Keyv from 'keyv'; +export declare const store: (storePath: string, ns?: string, opts?: any) => Keyv; +export declare const get: (key: string, storePath: string, ns?: string, opts?: any) => Promise; +export declare const set: (key: string, value: any, storePath: string, ns?: string, opts?: any) => Promise; +export declare const list: (key: string, value: any, storePath: string, ns?: string, opts?: any) => Promise; diff --git a/packages/ai-tools/dist/lib/tools/keyv.js b/packages/ai-tools/dist/lib/tools/keyv.js new file mode 100644 index 00000000..54bcd5ea --- /dev/null +++ b/packages/ai-tools/dist/lib/tools/keyv.js @@ -0,0 +1,21 @@ +import * as path from 'path'; +import Keyv from 'keyv'; +import KeyvSqlite from '@keyv/sqlite'; +import { resolve } from '@polymech/commons'; +export const store = (storePath, ns = 'ns-unknown', opts = {}) => { + const keyvSqlite = new KeyvSqlite(path.resolve(resolve(storePath))); + return new Keyv({ store: keyvSqlite, ttl: 5000, namespace: ns, ...opts }); +}; +export const get = async (key, storePath, ns = 'ns-unknown', opts = {}) => { + const keyv = store(storePath, ns, opts); + return await keyv.get(key); +}; +export const set = async (key, value, storePath, ns = 'ns-unknown', opts = {}) => { + const keyv = store(storePath, ns, opts); + return await keyv.set(key, value); +}; +export const list = async (key, value, storePath, ns = 'ns-unknown', opts = {}) => { + const keyv = store(storePath, ns, opts); + return await keyv.set(key, value); +}; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoia2V5di5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9saWIvdG9vbHMva2V5di50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssSUFBSSxNQUFNLE1BQU0sQ0FBQTtBQUM1QixPQUFPLElBQUksTUFBTSxNQUFNLENBQUE7QUFDdkIsT0FBTyxVQUFVLE1BQU0sY0FBYyxDQUFBO0FBRXJDLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQTtBQUUzQyxNQUFNLENBQUMsTUFBTSxLQUFLLEdBQUcsQ0FBQyxTQUFpQixFQUFFLEtBQWEsWUFBWSxFQUFFLE9BQVksRUFBRSxFQUFFLEVBQUU7SUFDbEYsTUFBTSxVQUFVLEdBQUcsSUFBSSxVQUFVLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFBO0lBQ25FLE9BQU8sSUFBSSxJQUFJLENBQUMsRUFBRSxLQUFLLEVBQUUsVUFBVSxFQUFFLEdBQUcsRUFBRSxJQUFJLEVBQUUsU0FBUyxFQUFFLEVBQUUsRUFBRSxHQUFHLElBQUksRUFBRSxDQUFDLENBQUE7QUFDN0UsQ0FBQyxDQUFBO0FBQ0QsTUFBTSxDQUFDLE1BQU0sR0FBRyxHQUFHLEtBQUssRUFBRSxHQUFXLEVBQUUsU0FBaUIsRUFBRSxLQUFhLFlBQVksRUFBRSxPQUFZLEVBQUUsRUFBRSxFQUFFO0lBQ25HLE1BQU0sSUFBSSxHQUFHLEtBQUssQ0FBQyxTQUFTLEVBQUUsRUFBRSxFQUFFLElBQUksQ0FBQyxDQUFBO0lBQ3ZDLE9BQU8sTUFBTSxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFBO0FBQzlCLENBQUMsQ0FBQTtBQUNELE1BQU0sQ0FBQyxNQUFNLEdBQUcsR0FBRyxLQUFLLEVBQUUsR0FBVyxFQUFFLEtBQVUsRUFBRSxTQUFpQixFQUFFLEtBQWEsWUFBWSxFQUFFLE9BQVksRUFBRSxFQUFFLEVBQUU7SUFDL0csTUFBTSxJQUFJLEdBQUcsS0FBSyxDQUFDLFNBQVMsRUFBRSxFQUFFLEVBQUUsSUFBSSxDQUFDLENBQUE7SUFDdkMsT0FBTyxNQUFNLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLEtBQUssQ0FBQyxDQUFBO0FBQ3JDLENBQUMsQ0FBQTtBQUNELE1BQU0sQ0FBQyxNQUFNLElBQUksR0FBRyxLQUFLLEVBQUUsR0FBVyxFQUFFLEtBQVUsRUFBRSxTQUFpQixFQUFFLEtBQWEsWUFBWSxFQUFFLE9BQVksRUFBRSxFQUFFLEVBQUU7SUFDaEgsTUFBTSxJQUFJLEdBQUcsS0FBSyxDQUFDLFNBQVMsRUFBRSxFQUFFLEVBQUUsSUFBSSxDQUFDLENBQUE7SUFDdkMsT0FBTyxNQUFNLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLEtBQUssQ0FBQyxDQUFBO0FBQ3JDLENBQUMsQ0FBQSJ9 \ No newline at end of file diff --git a/packages/ai-tools/dist/lib/tools/memory.d.ts b/packages/ai-tools/dist/lib/tools/memory.d.ts new file mode 100644 index 00000000..539fabc9 --- /dev/null +++ b/packages/ai-tools/dist/lib/tools/memory.d.ts @@ -0,0 +1,2 @@ +import { IKBotTask } from '../../types.js'; +export declare const tools: (target: string, options: IKBotTask) => Array; diff --git a/packages/ai-tools/dist/lib/tools/memory.js b/packages/ai-tools/dist/lib/tools/memory.js new file mode 100644 index 00000000..ac4d652d --- /dev/null +++ b/packages/ai-tools/dist/lib/tools/memory.js @@ -0,0 +1,354 @@ +import * as path from 'path'; +import { toolLogger } from '../../index.js'; +import { store, get, set } from './keyv.js'; +// Helper function to get storage path +const getStoragePath = (options) => { + // For now, use default path. Later this can be configured via options + return path.join(process.cwd(), 'memory.sqlite'); +}; +// Default collection name when none provided +const DEFAULT_COLLECTION = 'no-collection'; +// Helper function to process value based on format +const processValueForStorage = (value, format) => { + switch (format) { + case 'json': + try { + // Validate JSON by parsing and re-stringifying + JSON.parse(value); + return value; + } + catch (error) { + throw new Error('Invalid JSON format provided'); + } + case 'binary': + // For binary, we expect base64 encoded data + try { + // Validate base64 + Buffer.from(value, 'base64'); + return value; + } + catch (error) { + throw new Error('Invalid base64 format for binary data'); + } + case 'text': + default: + return value; + } +}; +// Helper function to create memory entry +const createMemoryEntry = (value, format) => { + const now = new Date().toISOString(); + return { + value: processValueForStorage(value, format), + meta: { + type: format, + created: now, + updated: now + } + }; +}; +export const tools = (target, options) => { + const logger = toolLogger('memory', options); + const storagePath = getStoragePath(options); + return [ + { + type: 'function', + function: { + name: 'memorize', + description: `Store information in memory as a key-value collection with format support. Supports text, JSON, and binary (base64) formats. + +Returns: { + success: boolean, + message: string, + meta: { + type: "text" | "json" | "binary", + created: string (ISO timestamp), + updated: string (ISO timestamp) + } +}`, + parameters: { + type: 'object', + properties: { + collection: { + type: 'string', + description: 'Collection name to organize related data (defaults to "no-collection" if not provided). Acts like a namespace.', + optional: true + }, + key: { + type: 'string', + description: 'Unique identifier for the data within the collection. Must be a string.' + }, + value: { + type: 'string', + description: 'The data to store. For format="text": any string. For format="json": valid JSON string. For format="binary": base64 encoded data.' + }, + format: { + type: 'string', + description: 'Data format type. "text" for plain text (default), "json" for JSON data (validates structure), "binary" for base64 encoded binary data.', + enum: ['text', 'json', 'binary'], + optional: true + } + }, + required: ['key', 'value'] + }, + function: async (params) => { + try { + const { collection = DEFAULT_COLLECTION, key, value, format = 'text' } = params; + logger.debug(`Tool::Memorize Storing ${key} in collection ${collection} as ${format}`); + const memoryEntry = createMemoryEntry(value, format); + await set(`${collection}:${key}`, memoryEntry, storagePath, collection); + return { + success: true, + message: `Stored ${key} in collection ${collection} as ${format}`, + meta: memoryEntry.meta + }; + } + catch (error) { + logger.error('Error storing memory', error); + return { + success: false, + message: error instanceof Error ? error.message : 'Unknown error occurred' + }; + } + }, + parse: JSON.parse + } + }, + { + type: 'function', + function: { + name: 'recall', + description: `Retrieve stored information from memory by collection and key, including format metadata. + +Returns: { + success: boolean, + value?: string (the stored data), + meta?: { + type: "text" | "json" | "binary", + created: string (ISO timestamp), + updated: string (ISO timestamp) + }, + key: string, + collection: string, + message?: string (error message if success=false) +}`, + parameters: { + type: 'object', + properties: { + collection: { + type: 'string', + description: 'Collection name to retrieve from (defaults to "no-collection" if not provided). Must match the collection used when storing.', + optional: true + }, + key: { + type: 'string', + description: 'The unique identifier of the data to retrieve. Must match the key used when storing.' + } + }, + required: ['key'] + }, + function: async (params) => { + try { + const { collection = DEFAULT_COLLECTION, key } = params; + logger.debug(`Tool::Recall Retrieving ${key} from collection ${collection}`); + const storedData = await get(`${collection}:${key}`, storagePath, collection); + if (storedData === undefined) { + return { success: false, message: `Key ${key} not found in collection ${collection}` }; + } + // Handle both old format (plain string) and new format (MemoryEntry) + let memoryEntry; + if (typeof storedData === 'string') { + // Legacy format - convert to new format + memoryEntry = { + value: storedData, + meta: { + type: 'text', + created: new Date().toISOString(), + updated: new Date().toISOString() + } + }; + } + else { + memoryEntry = storedData; + } + return { + success: true, + value: memoryEntry.value, + meta: memoryEntry.meta, + key, + collection + }; + } + catch (error) { + logger.error('Error retrieving memory', error); + return { + success: false, + message: error instanceof Error ? error.message : 'Unknown error occurred' + }; + } + }, + parse: JSON.parse + } + }, + { + type: 'function', + function: { + name: 'forget', + description: `Remove a specific key from memory collection. + +Returns: { + success: boolean, + message: string (confirmation or error message) +}`, + parameters: { + type: 'object', + properties: { + collection: { + type: 'string', + description: 'Collection name to remove from (defaults to "no-collection" if not provided). Must match the collection where the key was stored.', + optional: true + }, + key: { + type: 'string', + description: 'The unique identifier of the data to remove. Must match exactly the key used when storing.' + } + }, + required: ['key'] + }, + function: async (params) => { + try { + const { collection = DEFAULT_COLLECTION, key } = params; + logger.debug(`Tool::Forget Removing ${key} from collection ${collection}`); + const keyv = store(storagePath, collection); + const deleted = await keyv.delete(`${collection}:${key}`); + return { success: deleted, message: deleted ? `Removed ${key} from ${collection}` : `Key ${key} not found in ${collection}` }; + } + catch (error) { + logger.error('Error removing from memory', error); + return { + success: false, + message: error instanceof Error ? error.message : 'Unknown error occurred' + }; + } + }, + parse: JSON.parse + } + }, + { + type: 'function', + function: { + name: 'list_memories', + description: `List all keys in a specific collection using Keyv's iterator method. + +Returns: { + success: boolean, + collection: string (the collection name), + keys: string[] (array of key names in the collection), + entries: Array<{ + key: string, + meta?: { + type: "text" | "json" | "binary", + created: string (ISO timestamp), + updated: string (ISO timestamp) + } + }>, + count: number (total number of keys), + message?: string (info or error message) +}`, + parameters: { + type: 'object', + properties: { + collection: { + type: 'string', + description: 'Collection name to list keys from (defaults to "no-collection" if not provided). Will return all keys stored in this collection namespace.', + optional: true + } + }, + required: [] + }, + function: async (params) => { + try { + const { collection = DEFAULT_COLLECTION } = params; + logger.debug(`Tool::ListMemories Listing keys in collection ${collection}`); + // Create a Keyv instance for the specific collection to use iterator + const keyv = store(storagePath, collection); + const keys = []; + const entries = []; + try { + // Check if iterator method exists and use it + if (typeof keyv.iterator === 'function') { + try { + // Try calling iterator without arguments first + const iterator = keyv.iterator(); + for await (const [key, value] of iterator) { + // Remove the collection prefix from the key to get the clean key name + const cleanKey = key.replace(`${collection}:`, ''); + keys.push(cleanKey); + // Try to extract metadata if it's a MemoryEntry + let meta = undefined; + if (value && typeof value === 'object' && value.meta) { + meta = value.meta; + } + entries.push({ key: cleanKey, meta }); + } + } + catch (iteratorCallError) { + logger.warn(`Tool::ListMemories Iterator call failed:`, iteratorCallError); + // Fall through to the not available case + return { + success: true, + collection, + keys: [], + entries: [], + count: 0, + message: 'Iterator call failed. Unable to list keys.' + }; + } + } + else { + // Iterator not available, provide helpful message + logger.warn(`Tool::ListMemories Iterator method not available for Keyv instance`); + return { + success: true, + collection, + keys: [], + entries: [], + count: 0, + message: 'Iterator method not available in this Keyv version. Use individual key operations instead.' + }; + } + return { + success: true, + collection, + keys, + entries, + count: keys.length + }; + } + catch (iteratorError) { + // If iterator fails, fall back to returning basic info + logger.warn(`Tool::ListMemories Iterator failed for collection ${collection}:`, iteratorError); + return { + success: true, + collection, + keys: [], + entries: [], + count: 0, + message: 'Iterator failed or collection is empty' + }; + } + } + catch (error) { + logger.error('Error listing memories', error); + return { + success: false, + message: error instanceof Error ? error.message : 'Unknown error occurred' + }; + } + }, + parse: JSON.parse + } + } + ]; +}; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWVtb3J5LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2xpYi90b29scy9tZW1vcnkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLElBQUksTUFBTSxNQUFNLENBQUE7QUFJNUIsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGdCQUFnQixDQUFBO0FBRzNDLE9BQU8sRUFBRSxLQUFLLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxNQUFNLFdBQVcsQ0FBQTtBQUUzQyxzQ0FBc0M7QUFDdEMsTUFBTSxjQUFjLEdBQUcsQ0FBQyxPQUFrQixFQUFVLEVBQUU7SUFDbEQsc0VBQXNFO0lBQ3RFLE9BQU8sSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxFQUFFLEVBQUUsZUFBZSxDQUFDLENBQUM7QUFDckQsQ0FBQyxDQUFDO0FBRUYsNkNBQTZDO0FBQzdDLE1BQU0sa0JBQWtCLEdBQUcsZUFBZSxDQUFDO0FBZTNDLG1EQUFtRDtBQUNuRCxNQUFNLHNCQUFzQixHQUFHLENBQUMsS0FBYSxFQUFFLE1BQWtCLEVBQVUsRUFBRTtJQUN6RSxRQUFRLE1BQU0sRUFBRTtRQUNaLEtBQUssTUFBTTtZQUNQLElBQUk7Z0JBQ0EsK0NBQStDO2dCQUMvQyxJQUFJLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDO2dCQUNsQixPQUFPLEtBQUssQ0FBQzthQUNoQjtZQUFDLE9BQU8sS0FBSyxFQUFFO2dCQUNaLE1BQU0sSUFBSSxLQUFLLENBQUMsOEJBQThCLENBQUMsQ0FBQzthQUNuRDtRQUNMLEtBQUssUUFBUTtZQUNULDRDQUE0QztZQUM1QyxJQUFJO2dCQUNBLGtCQUFrQjtnQkFDbEIsTUFBTSxDQUFDLElBQUksQ0FBQyxLQUFLLEVBQUUsUUFBUSxDQUFDLENBQUM7Z0JBQzdCLE9BQU8sS0FBSyxDQUFDO2FBQ2hCO1lBQUMsT0FBTyxLQUFLLEVBQUU7Z0JBQ1osTUFBTSxJQUFJLEtBQUssQ0FBQyx1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 \ No newline at end of file diff --git a/packages/ai-tools/dist/lib/tools/tools.d.ts b/packages/ai-tools/dist/lib/tools/tools.d.ts index 8523e2ae..6e7dd073 100644 --- a/packages/ai-tools/dist/lib/tools/tools.d.ts +++ b/packages/ai-tools/dist/lib/tools/tools.d.ts @@ -7,4 +7,5 @@ export declare const tools: { user: (target: string, options: import("../../types.js").IKBotTask) => any[]; search: (target: string, options: import("../../types.js").IKBotTask) => any[]; web: (target: string, options: import("../../types.js").IKBotTask) => any[]; + memory: (target: string, options: import("../../types.js").IKBotTask) => any[]; }; diff --git a/packages/ai-tools/dist/lib/tools/tools.js b/packages/ai-tools/dist/lib/tools/tools.js index 2e48ad8f..36d1af6b 100644 --- a/packages/ai-tools/dist/lib/tools/tools.js +++ b/packages/ai-tools/dist/lib/tools/tools.js @@ -6,6 +6,7 @@ import { tools as interactTools } from './interact.js'; import { tools as userTools } from './user.js'; import { tools as search } from './search.js'; import { tools as webTools } from './web.js'; +import { tools as memoryTools } from './memory.js'; //import { tools as emailTools } from './email' export const tools = { fs: fsTools, @@ -16,6 +17,7 @@ export const tools = { user: userTools, search: search, web: webTools, + memory: memoryTools, // email: emailTools }; -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidG9vbHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvbGliL3Rvb2xzL3Rvb2xzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxLQUFLLElBQUksT0FBTyxFQUFFLE1BQU0sU0FBUyxDQUFBO0FBQzFDLE9BQU8sRUFBRSxLQUFLLElBQUksUUFBUSxFQUFFLE1BQU0sVUFBVSxDQUFBO0FBQzVDLE9BQU8sRUFBRSxLQUFLLElBQUksUUFBUSxFQUFFLE1BQU0sVUFBVSxDQUFBO0FBQzVDLE9BQU8sRUFBRSxLQUFLLElBQUksYUFBYSxFQUFFLE1BQU0sZUFBZSxDQUFBO0FBQ3RELE9BQU8sRUFBRSxLQUFLLElBQUksYUFBYSxFQUFFLE1BQU0sZUFBZSxDQUFBO0FBQ3RELE9BQU8sRUFBRSxLQUFLLElBQUksU0FBUyxFQUFFLE1BQU0sV0FBVyxDQUFBO0FBQzlDLE9BQU8sRUFBRSxLQUFLLElBQUksTUFBTSxFQUFFLE1BQU0sYUFBYSxDQUFBO0FBQzdDLE9BQU8sRUFBRSxLQUFLLElBQUksUUFBUSxFQUFFLE1BQU0sVUFBVSxDQUFBO0FBQzVDLCtDQUErQztBQUUvQyxNQUFNLENBQUMsTUFBTSxLQUFLLEdBQUc7SUFDakIsRUFBRSxFQUFFLE9BQU87SUFDWCxHQUFHLEVBQUUsUUFBUTtJQUNiLEdBQUcsRUFBRSxRQUFRO0lBQ2IsUUFBUSxFQUFFLGFBQWE7SUFDdkIsUUFBUSxFQUFFLGFBQWE7SUFDdkIsSUFBSSxFQUFFLFNBQVM7SUFDZixNQUFNLEVBQUUsTUFBTTtJQUNkLEdBQUcsRUFBRSxRQUFRO0lBQ2Isb0JBQW9CO0NBQ3ZCLENBQUEifQ== \ No newline at end of file +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidG9vbHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvbGliL3Rvb2xzL3Rvb2xzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxLQUFLLElBQUksT0FBTyxFQUFFLE1BQU0sU0FBUyxDQUFBO0FBQzFDLE9BQU8sRUFBRSxLQUFLLElBQUksUUFBUSxFQUFFLE1BQU0sVUFBVSxDQUFBO0FBQzVDLE9BQU8sRUFBRSxLQUFLLElBQUksUUFBUSxFQUFFLE1BQU0sVUFBVSxDQUFBO0FBQzVDLE9BQU8sRUFBRSxLQUFLLElBQUksYUFBYSxFQUFFLE1BQU0sZUFBZSxDQUFBO0FBQ3RELE9BQU8sRUFBRSxLQUFLLElBQUksYUFBYSxFQUFFLE1BQU0sZUFBZSxDQUFBO0FBQ3RELE9BQU8sRUFBRSxLQUFLLElBQUksU0FBUyxFQUFFLE1BQU0sV0FBVyxDQUFBO0FBQzlDLE9BQU8sRUFBRSxLQUFLLElBQUksTUFBTSxFQUFFLE1BQU0sYUFBYSxDQUFBO0FBQzdDLE9BQU8sRUFBRSxLQUFLLElBQUksUUFBUSxFQUFFLE1BQU0sVUFBVSxDQUFBO0FBQzVDLE9BQU8sRUFBRSxLQUFLLElBQUksV0FBVyxFQUFFLE1BQU0sYUFBYSxDQUFBO0FBQ2xELCtDQUErQztBQUUvQyxNQUFNLENBQUMsTUFBTSxLQUFLLEdBQUc7SUFDakIsRUFBRSxFQUFFLE9BQU87SUFDWCxHQUFHLEVBQUUsUUFBUTtJQUNiLEdBQUcsRUFBRSxRQUFRO0lBQ2IsUUFBUSxFQUFFLGFBQWE7SUFDdkIsUUFBUSxFQUFFLGFBQWE7SUFDdkIsSUFBSSxFQUFFLFNBQVM7SUFDZixNQUFNLEVBQUUsTUFBTTtJQUNkLEdBQUcsRUFBRSxRQUFRO0lBQ2IsTUFBTSxFQUFFLFdBQVc7SUFDbkIsb0JBQW9CO0NBQ3ZCLENBQUEifQ== \ No newline at end of file diff --git a/packages/ai-tools/dist/types_kbot.d.ts b/packages/ai-tools/dist/types_kbot.d.ts index db31cacf..0fe855a7 100644 --- a/packages/ai-tools/dist/types_kbot.d.ts +++ b/packages/ai-tools/dist/types_kbot.d.ts @@ -8,7 +8,7 @@ export interface IKBotOptions { /** Optional destination path for the result, will substitute ${MODEL_NAME} and ${ROUTER} in the path. Optional, used for "completion" mode */ dst?: string | undefined; /** How to handle output if --dst file already exists: "concat" (append) or "merge" (try to merge structures if possible, otherwise append). Only used if --dst is specified. */ - append?: ("concat" | "merge") | undefined; + append?: ("concat" | "merge" | "replace") | undefined; /** Specify how to wrap the output, "meta (file name, absolute path, cwd)" or "none". */ wrap?: "meta" | "none"; /** Iterate over items, supported: GLOB | Path to JSON File | array of strings (comma separated). To test different models, use --each="gpt-3.5-turbo,gpt-4o", the actual string will exposed as variable `ITEM`, eg: --dst="${ITEM}-output.md" */ @@ -31,8 +31,6 @@ export interface IKBotOptions {   OpenRouter models:  - 01-ai/yi-large | paid - aetherwiing/mn-starcannon-12b | paid agentica-org/deepcoder-14b-preview | paid agentica-org/deepcoder-14b-preview:free | free ai21/jamba-1.6-large | paid @@ -48,11 +46,8 @@ export interface IKBotOptions { anthropic/claude-3-haiku:beta | paid anthropic/claude-3-opus | paid anthropic/claude-3-opus:beta | paid - anthropic/claude-3-sonnet | paid - anthropic/claude-3-sonnet:beta | paid anthropic/claude-3.5-haiku | paid anthropic/claude-3.5-haiku-20241022 | paid - anthropic/claude-3.5-haiku-20241022:beta | paid anthropic/claude-3.5-haiku:beta | paid anthropic/claude-3.5-sonnet | paid anthropic/claude-3.5-sonnet-20240620 | paid @@ -62,23 +57,17 @@ export interface IKBotOptions { anthropic/claude-3.7-sonnet:beta | paid anthropic/claude-3.7-sonnet:thinking | paid anthropic/claude-opus-4 | paid + anthropic/claude-opus-4.1 | paid anthropic/claude-sonnet-4 | paid - anthropic/claude-2 | paid - anthropic/claude-2:beta | paid - anthropic/claude-2.0 | paid - anthropic/claude-2.0:beta | paid - anthropic/claude-2.1 | paid - anthropic/claude-2.1:beta | paid - arcee-ai/arcee-blitz | paid - arcee-ai/caller-large | paid arcee-ai/coder-large | paid arcee-ai/maestro-reasoning | paid arcee-ai/spotlight | paid arcee-ai/virtuoso-large | paid - arcee-ai/virtuoso-medium-v2 | paid + arliai/qwq-32b-arliai-rpr-v1 | paid arliai/qwq-32b-arliai-rpr-v1:free | free openrouter/auto | paid baidu/ernie-4.5-300b-a47b | paid + bytedance/ui-tars-1.5-7b | paid cohere/command | paid cohere/command-a | paid cohere/command-r | paid @@ -92,10 +81,9 @@ export interface IKBotOptions { deepseek/deepseek-r1-0528-qwen3-8b | paid deepseek/deepseek-r1-0528-qwen3-8b:free | free deepseek/deepseek-chat | paid - deepseek/deepseek-chat:free | free deepseek/deepseek-chat-v3-0324 | paid deepseek/deepseek-chat-v3-0324:free | free - deepseek/deepseek-v3-base:free | free + deepseek/deepseek-v3-base | paid deepseek/deepseek-r1 | paid deepseek/deepseek-r1:free | free deepseek/deepseek-r1-0528 | paid @@ -109,12 +97,11 @@ export interface IKBotOptions { deepseek/deepseek-r1-distill-qwen-32b | paid deepseek/deepseek-r1-distill-qwen-7b | paid cognitivecomputations/dolphin-mixtral-8x22b | paid + cognitivecomputations/dolphin3.0-mistral-24b | paid cognitivecomputations/dolphin3.0-mistral-24b:free | free cognitivecomputations/dolphin3.0-r1-mistral-24b | paid cognitivecomputations/dolphin3.0-r1-mistral-24b:free | free eleutherai/llemma_7b | paid - eva-unit-01/eva-llama-3.33-70b | paid - eva-unit-01/eva-qwen-2.5-72b | paid sao10k/fimbulvetr-11b-v2 | paid alpindale/goliath-120b | paid google/gemini-flash-1.5 | paid @@ -124,6 +111,7 @@ export interface IKBotOptions { google/gemini-2.0-flash-exp:free | free google/gemini-2.0-flash-lite-001 | paid google/gemini-2.5-flash | paid + google/gemini-2.5-flash-lite | paid google/gemini-2.5-flash-lite-preview-06-17 | paid google/gemini-2.5-pro | paid google/gemini-2.5-pro-exp-03-25 | paid @@ -141,6 +129,7 @@ export interface IKBotOptions { google/gemma-3n-e2b-it:free | free google/gemma-3n-e4b-it | paid google/gemma-3n-e4b-it:free | free + openrouter/horizon-beta | paid inception/mercury | paid inception/mercury-coder | paid infermatic/mn-inferor-12b | paid @@ -151,7 +140,6 @@ export interface IKBotOptions { liquid/lfm-40b | paid liquid/lfm-7b | paid meta-llama/llama-guard-3-8b | paid - alpindale/magnum-72b | paid anthracite-org/magnum-v2-72b | paid anthracite-org/magnum-v4-72b | paid mancer/weaver | paid @@ -174,6 +162,7 @@ export interface IKBotOptions { meta-llama/llama-4-scout | paid meta-llama/llama-guard-4-12b | paid meta-llama/llama-guard-2-8b | paid + microsoft/mai-ds-r1 | paid microsoft/mai-ds-r1:free | free microsoft/phi-4 | paid microsoft/phi-4-multimodal-instruct | paid @@ -187,10 +176,10 @@ export interface IKBotOptions { mistralai/mistral-large | paid mistralai/mistral-large-2407 | paid mistralai/mistral-large-2411 | paid - nothingiisreal/mn-celeste-12b | paid mistralai/mistral-small | paid mistralai/mistral-tiny | paid mistralai/codestral-2501 | paid + mistralai/codestral-2508 | paid mistralai/devstral-medium | paid mistralai/devstral-small | paid mistralai/devstral-small-2505 | paid @@ -219,10 +208,10 @@ export interface IKBotOptions { mistralai/pixtral-12b | paid mistralai/pixtral-large-2411 | paid mistralai/mistral-saba | paid + moonshotai/kimi-vl-a3b-thinking | paid moonshotai/kimi-vl-a3b-thinking:free | free moonshotai/kimi-k2 | paid moonshotai/kimi-k2:free | free - morph/morph-v2 | paid morph/morph-v3-fast | paid morph/morph-v3-large | paid gryphe/mythomax-l2-13b | paid @@ -230,6 +219,7 @@ export interface IKBotOptions { neversleep/llama-3.1-lumimaid-8b | paid neversleep/noromaid-20b | paid nousresearch/deephermes-3-llama-3-8b-preview:free | free + nousresearch/deephermes-3-mistral-24b-preview | paid nousresearch/nous-hermes-2-mixtral-8x7b-dpo | paid nousresearch/hermes-3-llama-3.1-405b | paid nousresearch/hermes-3-llama-3.1-70b | paid @@ -240,6 +230,8 @@ export interface IKBotOptions { nvidia/llama-3.3-nemotron-super-49b-v1 | paid openai/chatgpt-4o-latest | paid openai/codex-mini | paid + openai/gpt-oss-120b | paid + openai/gpt-oss-20b | paid openai/gpt-3.5-turbo | paid openai/gpt-3.5-turbo-0613 | paid openai/gpt-3.5-turbo-16k | paid @@ -264,8 +256,6 @@ export interface IKBotOptions { openai/o1 | paid openai/o1-mini | paid openai/o1-mini-2024-09-12 | paid - openai/o1-preview | paid - openai/o1-preview-2024-09-12 | paid openai/o1-pro | paid openai/o3 | paid openai/o3-mini | paid @@ -281,6 +271,7 @@ export interface IKBotOptions { perplexity/sonar-reasoning | paid perplexity/sonar-reasoning-pro | paid pygmalionai/mythalion-13b | paid + featherless/qwerky-72b:free | free qwen/qwen-2-72b-instruct | paid qwen/qwen-vl-max | paid qwen/qwen-vl-plus | paid @@ -296,13 +287,16 @@ export interface IKBotOptions { qwen/qwen3-14b:free | free qwen/qwen3-235b-a22b | paid qwen/qwen3-235b-a22b:free | free + qwen/qwen3-235b-a22b-2507 | paid + qwen/qwen3-235b-a22b-thinking-2507 | paid qwen/qwen3-30b-a3b | paid qwen/qwen3-30b-a3b:free | free + qwen/qwen3-30b-a3b-instruct-2507 | paid qwen/qwen3-32b | paid - qwen/qwen3-32b:free | free qwen/qwen3-4b:free | free qwen/qwen3-8b | paid qwen/qwen3-8b:free | free + qwen/qwen3-coder | paid qwen/qwq-32b | paid qwen/qwq-32b:free | free qwen/qwq-32b-preview | paid @@ -311,16 +305,14 @@ export interface IKBotOptions { qwen/qwen-2.5-7b-instruct | paid qwen/qwen-2.5-coder-32b-instruct | paid qwen/qwen-2.5-coder-32b-instruct:free | free - featherless/qwerky-72b:free | free - rekaai/reka-flash-3 | paid rekaai/reka-flash-3:free | free undi95/remm-slerp-l2-13b | paid sao10k/l3-lunaris-8b | paid sao10k/l3-euryale-70b | paid sao10k/l3.1-euryale-70b | paid sao10k/l3.3-euryale-70b | paid - sarvamai/sarvam-m | paid sarvamai/sarvam-m:free | free + shisa-ai/shisa-v2-llama3.3-70b | paid shisa-ai/shisa-v2-llama3.3-70b:free | free raifle/sorcererlm-8x22b | paid switchpoint/router | paid @@ -333,9 +325,9 @@ export interface IKBotOptions { thedrummer/unslopnemo-12b | paid thedrummer/valkyrie-49b-v1 | paid thudm/glm-4-32b | paid - thudm/glm-4-32b:free | free thudm/glm-4.1v-9b-thinking | paid thudm/glm-z1-32b:free | free + tngtech/deepseek-r1t-chimera | paid tngtech/deepseek-r1t-chimera:free | free tngtech/deepseek-r1t2-chimera:free | free undi95/toppy-m-7b | paid @@ -350,6 +342,10 @@ export interface IKBotOptions { x-ai/grok-3-mini-beta | paid x-ai/grok-4 | paid x-ai/grok-vision-beta | paid + z-ai/glm-4-32b | paid + z-ai/glm-4.5 | paid + z-ai/glm-4.5-air | paid + z-ai/glm-4.5-air:free | free   OpenAI models:  @@ -408,8 +404,6 @@ export interface IKBotOptions { o1-2024-12-17 o1-mini o1-mini-2024-09-12 - o1-preview - o1-preview-2024-09-12 o1-pro o1-pro-2025-03-19 o3-mini diff --git a/packages/ai-tools/package-lock.json b/packages/ai-tools/package-lock.json index f7413208..2fdff45c 100644 --- a/packages/ai-tools/package-lock.json +++ b/packages/ai-tools/package-lock.json @@ -10,6 +10,7 @@ "dependencies": { "@datalust/winston-seq": "^2.0.0", "@inquirer/prompts": "^7.3.2", + "@keyv/sqlite": "^4.0.5", "@polymech/commons": "file:../commons", "@polymech/core": "file:../core", "@polymech/fs": "file:../fs", @@ -20,6 +21,8 @@ "glob": "^11.0.1", "inquirer": "^12.2.0", "jsdom": "^25.0.1", + "keyv": "^5.5.0", + "keyv-file": "^5.1.3", "marked": "^15.0.4", "mime-types": "^2.1.35", "nodemailer": "^6.9.16", @@ -3302,6 +3305,13 @@ "winston": "^3.0.0" } }, + "node_modules/@gar/promisify": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", + "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", + "license": "MIT", + "optional": true + }, "node_modules/@inquirer/checkbox": { "version": "4.1.2", "license": "MIT", @@ -3640,6 +3650,27 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "node_modules/@keyv/serialize": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@keyv/serialize/-/serialize-1.1.0.tgz", + "integrity": "sha512-RlDgexML7Z63Q8BSaqhXdCYNBy/JQnqYIwxofUrNLGCblOMHp+xux2Q8nLMLlPpgHQPoU0Do8Z6btCpRBEqZ8g==", + "license": "MIT" + }, + "node_modules/@keyv/sqlite": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@keyv/sqlite/-/sqlite-4.0.5.tgz", + "integrity": "sha512-Q7Ye2p+wDA1ufQ4SHuWfZk0c4oZJ5y73AZ28zHLWeMqgPbIDItK0dMvM5lL+B1Tl4nBPbPO00F+f7dQrS9u/IQ==", + "license": "MIT", + "dependencies": { + "sqlite3": "^5.1.7" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "keyv": "^5.3.4" + } + }, "node_modules/@kwsites/file-exists": { "version": "1.1.1", "license": "MIT", @@ -3655,6 +3686,45 @@ "version": "2.2.0", "license": "BSD-2-Clause" }, + "node_modules/@npmcli/fs": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.1.tgz", + "integrity": "sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==", + "license": "ISC", + "optional": true, + "dependencies": { + "@gar/promisify": "^1.0.1", + "semver": "^7.3.5" + } + }, + "node_modules/@npmcli/move-file": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz", + "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==", + "deprecated": "This functionality has been moved to @npmcli/fs", + "license": "MIT", + "optional": true, + "dependencies": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@npmcli/move-file/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "license": "MIT", + "optional": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@polymech/commons": { "resolved": "../commons", "link": true @@ -3691,6 +3761,16 @@ "node": ">=18" } }, + "node_modules/@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 6" + } + }, "node_modules/@tootallnate/quickjs-emscripten": { "version": "0.23.0", "license": "MIT", @@ -3786,6 +3866,13 @@ "@types/node": "*" } }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "license": "ISC", + "optional": true + }, "node_modules/abort-controller": { "version": "3.0.0", "license": "MIT", @@ -3825,6 +3912,33 @@ "node": ">= 14" } }, + "node_modules/agentkeepalive": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.6.0.tgz", + "integrity": "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "license": "MIT", + "optional": true, + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/ansi-escapes": { "version": "4.3.2", "license": "MIT", @@ -3885,6 +3999,28 @@ "version": "1.1.4", "license": "MIT" }, + "node_modules/aproba": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.1.0.tgz", + "integrity": "sha512-tLIEcj5GuR2RSTnxNKdkK0dJ/GrC7P38sUkiDmDuHfsHmbagTFAxDVIBltoklXEVIQ/f14IL8IMJ5pn9Hez1Ew==", + "license": "ISC", + "optional": true + }, + "node_modules/are-we-there-yet": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", + "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", + "deprecated": "This package is no longer supported.", + "license": "ISC", + "optional": true, + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, "node_modules/arg": { "version": "4.1.3", "dev": true, @@ -3986,6 +4122,26 @@ } } }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, "node_modules/basic-ftp": { "version": "5.0.5", "license": "MIT", @@ -3994,6 +4150,26 @@ "node": ">=10.0.0" } }, + "node_modules/bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "license": "MIT", + "dependencies": { + "file-uri-to-path": "1.0.0" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "license": "MIT", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, "node_modules/boolbase": { "version": "1.0.0", "license": "ISC" @@ -4006,6 +4182,30 @@ "concat-map": "0.0.1" } }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, "node_modules/buffer-crc32": { "version": "0.2.13", "license": "MIT", @@ -4014,6 +4214,113 @@ "node": "*" } }, + "node_modules/cacache": { + "version": "15.3.0", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz", + "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", + "license": "ISC", + "optional": true, + "dependencies": { + "@npmcli/fs": "^1.0.0", + "@npmcli/move-file": "^1.0.1", + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "glob": "^7.1.4", + "infer-owner": "^1.0.4", + "lru-cache": "^6.0.0", + "minipass": "^3.1.1", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.2", + "mkdirp": "^1.0.3", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^8.0.1", + "tar": "^6.0.2", + "unique-filename": "^1.1.1" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/cacache/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "license": "ISC", + "optional": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/cacache/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "license": "ISC", + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cacache/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cacache/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "license": "MIT", + "optional": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cacache/node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/call-bind-apply-helpers": { "version": "1.0.2", "license": "MIT", @@ -4075,6 +4382,15 @@ "url": "https://github.com/sponsors/fb55" } }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, "node_modules/chromium-bidi": { "version": "1.3.0", "license": "Apache-2.0", @@ -4087,6 +4403,16 @@ "devtools-protocol": "*" } }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=6" + } + }, "node_modules/cli-width": { "version": "4.1.0", "license": "ISC", @@ -4181,6 +4507,16 @@ "simple-swizzle": "^0.2.2" } }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "license": "ISC", + "optional": true, + "bin": { + "color-support": "bin.js" + } + }, "node_modules/colorspace": { "version": "1.1.4", "license": "MIT", @@ -4210,6 +4546,13 @@ "version": "0.0.1", "license": "MIT" }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", + "license": "ISC", + "optional": true + }, "node_modules/cosmiconfig": { "version": "9.0.0", "license": "MIT", @@ -4329,6 +4672,30 @@ "version": "10.5.0", "license": "MIT" }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "license": "MIT", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/degenerator": { "version": "5.0.1", "license": "MIT", @@ -4349,6 +4716,22 @@ "node": ">=0.4.0" } }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "license": "MIT", + "optional": true + }, + "node_modules/detect-libc": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz", + "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, "node_modules/devtools-protocol": { "version": "0.0.1402036", "license": "BSD-3-Clause", @@ -4433,6 +4816,16 @@ "version": "2.0.0", "license": "MIT" }, + "node_modules/encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "license": "MIT", + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, "node_modules/encoding-sniffer": { "version": "0.2.0", "license": "MIT", @@ -4447,7 +4840,6 @@ "node_modules/end-of-stream": { "version": "1.4.4", "license": "MIT", - "optional": true, "dependencies": { "once": "^1.4.0" } @@ -4470,6 +4862,13 @@ "node": ">=6" } }, + "node_modules/err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "license": "MIT", + "optional": true + }, "node_modules/error-ex": { "version": "1.3.2", "license": "MIT", @@ -4577,6 +4976,15 @@ "node": ">=6" } }, + "node_modules/expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "license": "(MIT OR WTFPL)", + "engines": { + "node": ">=6" + } + }, "node_modules/external-editor": { "version": "3.1.0", "license": "MIT", @@ -4635,6 +5043,12 @@ "version": "4.2.3", "license": "MIT" }, + "node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "license": "MIT" + }, "node_modules/find-up": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-7.0.0.tgz", @@ -4701,6 +5115,47 @@ "node": ">= 6" } }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "license": "MIT" + }, + "node_modules/fs-extra": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz", + "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/fs.realpath": { "version": "1.0.0", "license": "ISC" @@ -4712,6 +5167,79 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/gauge": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", + "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", + "deprecated": "This package is no longer supported.", + "license": "ISC", + "optional": true, + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.3", + "console-control-strings": "^1.1.0", + "has-unicode": "^2.0.1", + "signal-exit": "^3.0.7", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/gauge/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/gauge/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT", + "optional": true + }, + "node_modules/gauge/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "license": "ISC", + "optional": true + }, + "node_modules/gauge/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "optional": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/gauge/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "optional": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/get-caller-file": { "version": "2.0.5", "license": "ISC", @@ -4779,6 +5307,12 @@ "node": ">= 14" } }, + "node_modules/github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", + "license": "MIT" + }, "node_modules/glob": { "version": "11.0.1", "license": "ISC", @@ -4830,6 +5364,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, "node_modules/has-symbols": { "version": "1.1.0", "license": "MIT", @@ -4853,6 +5393,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "license": "ISC", + "optional": true + }, "node_modules/hasown": { "version": "2.0.2", "license": "MIT", @@ -4890,6 +5437,13 @@ "entities": "^4.5.0" } }, + "node_modules/http-cache-semantics": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", + "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", + "license": "BSD-2-Clause", + "optional": true + }, "node_modules/http-proxy-agent": { "version": "7.0.2", "license": "MIT", @@ -4912,6 +5466,16 @@ "node": ">= 14" } }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "ms": "^2.0.0" + } + }, "node_modules/iconv-lite": { "version": "0.6.3", "license": "MIT", @@ -4922,6 +5486,26 @@ "node": ">=0.10.0" } }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, "node_modules/import-fresh": { "version": "3.3.1", "license": "MIT", @@ -4937,6 +5521,33 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", + "license": "ISC", + "optional": true + }, "node_modules/inflight": { "version": "1.0.6", "license": "ISC", @@ -4949,6 +5560,12 @@ "version": "2.0.4", "license": "ISC" }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "license": "ISC" + }, "node_modules/inquirer": { "version": "12.4.2", "license": "MIT", @@ -4997,6 +5614,13 @@ "node": ">=8" } }, + "node_modules/is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", + "license": "MIT", + "optional": true + }, "node_modules/is-potential-custom-element-name": { "version": "1.0.1", "license": "MIT" @@ -5092,6 +5716,41 @@ "license": "MIT", "optional": true }, + "node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "license": "MIT", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/keyv": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-5.5.0.tgz", + "integrity": "sha512-QG7qR2tijh1ftOvClut4YKKg1iW6cx3GZsKoGyJPxHkGWK9oJhG9P3j5deP0QQOGDowBMVQFaP+Vm4NpGYvmIQ==", + "license": "MIT", + "dependencies": { + "@keyv/serialize": "^1.1.0" + } + }, + "node_modules/keyv-file": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/keyv-file/-/keyv-file-5.1.3.tgz", + "integrity": "sha512-RmoLDAtY0j9kuMtpVcoslCRKzT3nwT32adyafJdjAC7Wg9sS5DpdeDN8A1gHFXmm4F9xr7AO5+MhyoPeKihZIA==", + "license": "MIT", + "dependencies": { + "@keyv/serialize": "^1.0.1", + "fs-extra": "^4.0.1", + "tslib": "^1.14.1" + } + }, + "node_modules/keyv-file/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "license": "0BSD" + }, "node_modules/kuler": { "version": "2.0.0", "license": "MIT" @@ -5140,6 +5799,117 @@ "dev": true, "license": "ISC" }, + "node_modules/make-fetch-happen": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz", + "integrity": "sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==", + "license": "ISC", + "optional": true, + "dependencies": { + "agentkeepalive": "^4.1.3", + "cacache": "^15.2.0", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^6.0.0", + "minipass": "^3.1.3", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^1.3.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.2", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^6.0.0", + "ssri": "^8.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/make-fetch-happen/node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/make-fetch-happen/node_modules/http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "license": "MIT", + "optional": true, + "dependencies": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/make-fetch-happen/node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "license": "MIT", + "optional": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/make-fetch-happen/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "license": "ISC", + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-fetch-happen/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/make-fetch-happen/node_modules/socks-proxy-agent": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.2.1.tgz", + "integrity": "sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" + }, + "engines": { + "node": ">= 10" + } + }, "node_modules/marked": { "version": "15.0.7", "license": "MIT", @@ -5174,6 +5944,18 @@ "node": ">= 0.6" } }, + "node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/minimatch": { "version": "3.1.2", "license": "ISC", @@ -5198,6 +5980,166 @@ "node": ">=16 || 14 >=14.17" } }, + "node_modules/minipass-collect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", + "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "license": "ISC", + "optional": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-collect/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-fetch": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-1.4.1.tgz", + "integrity": "sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==", + "license": "MIT", + "optional": true, + "dependencies": { + "minipass": "^3.1.0", + "minipass-sized": "^1.0.3", + "minizlib": "^2.0.0" + }, + "engines": { + "node": ">=8" + }, + "optionalDependencies": { + "encoding": "^0.1.12" + } + }, + "node_modules/minipass-fetch/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "license": "ISC", + "optional": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-flush/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "license": "ISC", + "optional": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-pipeline/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "license": "ISC", + "optional": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "license": "MIT", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/mitt": { "version": "3.0.1", "license": "MIT", @@ -5213,6 +6155,12 @@ "mkdirp": "bin/cmd.js" } }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "license": "MIT" + }, "node_modules/ms": { "version": "2.1.3", "license": "MIT" @@ -5224,6 +6172,22 @@ "node": "^18.17.0 || >=20.5.0" } }, + "node_modules/napi-build-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz", + "integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==", + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", + "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/netmask": { "version": "2.0.2", "license": "MIT", @@ -5232,6 +6196,24 @@ "node": ">= 0.4.0" } }, + "node_modules/node-abi": { + "version": "3.75.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.75.0.tgz", + "integrity": "sha512-OhYaY5sDsIka7H7AtijtI9jwGYLyl29eQn/W623DiN/MIv5sUqc4g7BIDThX+gb7di9f6xK02nkp8sdfFWZLTg==", + "license": "MIT", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "license": "MIT" + }, "node_modules/node-fetch": { "version": "2.7.0", "license": "MIT", @@ -5266,6 +6248,53 @@ "webidl-conversions": "^3.0.0" } }, + "node_modules/node-gyp": { + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-8.4.1.tgz", + "integrity": "sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w==", + "license": "MIT", + "optional": true, + "dependencies": { + "env-paths": "^2.2.0", + "glob": "^7.1.4", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^9.1.0", + "nopt": "^5.0.0", + "npmlog": "^6.0.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^2.0.2" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": ">= 10.12.0" + } + }, + "node_modules/node-gyp/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "license": "ISC", + "optional": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/nodemailer": { "version": "6.10.0", "license": "MIT-0", @@ -5273,6 +6302,39 @@ "node": ">=6.0.0" } }, + "node_modules/nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "license": "ISC", + "optional": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/npmlog": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", + "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", + "deprecated": "This package is no longer supported.", + "license": "ISC", + "optional": true, + "dependencies": { + "are-we-there-yet": "^3.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^4.0.3", + "set-blocking": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, "node_modules/nth-check": { "version": "2.1.1", "license": "BSD-2-Clause", @@ -5516,6 +6578,66 @@ "license": "ISC", "optional": true }, + "node_modules/prebuild-install": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz", + "integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==", + "license": "MIT", + "dependencies": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^2.0.0", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + }, + "bin": { + "prebuild-install": "bin.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/prebuild-install/node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "license": "ISC" + }, + "node_modules/prebuild-install/node_modules/tar-fs": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.3.tgz", + "integrity": "sha512-090nwYJDmlhwFwEW3QQl+vaNnxsO2yVsd45eTKRBzSzu+hlb1w2K9inVq5b0ngXuLVqQ4ApvsUHHnu/zQNkWAg==", + "license": "MIT", + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/prebuild-install/node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "license": "MIT", + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/progress": { "version": "2.0.3", "license": "MIT", @@ -5524,6 +6646,27 @@ "node": ">=0.4.0" } }, + "node_modules/promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", + "license": "ISC", + "optional": true + }, + "node_modules/promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "license": "MIT", + "optional": true, + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/proxy-agent": { "version": "6.5.0", "license": "MIT", @@ -5557,7 +6700,6 @@ "node_modules/pump": { "version": "3.0.2", "license": "MIT", - "optional": true, "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" @@ -5606,6 +6748,35 @@ "node": ">=18" } }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/require-directory": { "version": "2.1.1", "license": "MIT", @@ -5621,6 +6792,55 @@ "node": ">=4" } }, + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "license": "ISC", + "optional": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "license": "ISC", + "optional": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/rotating-file-stream": { "version": "3.2.6", "license": "MIT", @@ -5651,6 +6871,8 @@ }, "node_modules/safe-buffer": { "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "funding": [ { "type": "github", @@ -5704,7 +6926,6 @@ "node_modules/semver": { "version": "7.7.1", "license": "ISC", - "optional": true, "bin": { "semver": "bin/semver.js" }, @@ -5723,6 +6944,13 @@ "node": ">=14.18" } }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "license": "ISC", + "optional": true + }, "node_modules/shebang-command": { "version": "2.0.0", "license": "MIT", @@ -5764,6 +6992,51 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, "node_modules/simple-git": { "version": "3.27.0", "license": "MIT", @@ -5836,6 +7109,56 @@ "license": "BSD-3-Clause", "optional": true }, + "node_modules/sqlite3": { + "version": "5.1.7", + "resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-5.1.7.tgz", + "integrity": "sha512-GGIyOiFaG+TUra3JIfkI/zGP8yZYLPQ0pl1bH+ODjiX57sPhrLU5sQJn1y9bDKZUFYkX1crlrPfSYt0BKKdkog==", + "hasInstallScript": true, + "license": "BSD-3-Clause", + "dependencies": { + "bindings": "^1.5.0", + "node-addon-api": "^7.0.0", + "prebuild-install": "^7.1.1", + "tar": "^6.1.11" + }, + "optionalDependencies": { + "node-gyp": "8.x" + }, + "peerDependencies": { + "node-gyp": "8.x" + }, + "peerDependenciesMeta": { + "node-gyp": { + "optional": true + } + } + }, + "node_modules/ssri": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz", + "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", + "license": "ISC", + "optional": true, + "dependencies": { + "minipass": "^3.1.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/ssri/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/stack-trace": { "version": "0.0.10", "license": "MIT", @@ -5855,6 +7178,15 @@ "bare-events": "^2.2.0" } }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, "node_modules/string-width": { "version": "5.1.2", "license": "MIT", @@ -5935,6 +7267,15 @@ "node": ">=8" } }, + "node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/supports-color": { "version": "10.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-10.0.0.tgz", @@ -5951,6 +7292,23 @@ "version": "3.2.4", "license": "MIT" }, + "node_modules/tar": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "license": "ISC", + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/tar-fs": { "version": "3.0.8", "license": "MIT", @@ -5974,6 +7332,27 @@ "streamx": "^2.15.0" } }, + "node_modules/tar/node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "license": "ISC", + "engines": { + "node": ">=8" + } + }, + "node_modules/tar/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/temp": { "version": "0.9.4", "license": "MIT", @@ -6132,6 +7511,18 @@ "url": "https://github.com/fullstack-build/tslog?sponsor=1" } }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, "node_modules/turndown": { "version": "7.2.0", "license": "MIT", @@ -6190,6 +7581,35 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/unique-filename": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "license": "ISC", + "optional": true, + "dependencies": { + "unique-slug": "^2.0.0" + } + }, + "node_modules/unique-slug": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", + "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "license": "ISC", + "optional": true, + "dependencies": { + "imurmurhash": "^0.1.4" + } + }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "license": "MIT" @@ -6257,6 +7677,61 @@ "node": ">= 8" } }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "license": "ISC", + "optional": true, + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "node_modules/wide-align/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/wide-align/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT", + "optional": true + }, + "node_modules/wide-align/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "optional": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wide-align/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "optional": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/winston": { "version": "3.17.0", "license": "MIT", @@ -6289,44 +7764,6 @@ "node": ">= 12.0.0" } }, - "node_modules/winston-transport/node_modules/readable-stream": { - "version": "3.6.2", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/winston-transport/node_modules/string_decoder": { - "version": "1.3.0", - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/winston/node_modules/readable-stream": { - "version": "3.6.2", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/winston/node_modules/string_decoder": { - "version": "1.3.0", - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, "node_modules/wrap-ansi": { "version": "6.2.0", "license": "MIT", @@ -6462,6 +7899,12 @@ "node": ">=10" } }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC" + }, "node_modules/yargs": { "version": "17.7.2", "license": "MIT", diff --git a/packages/ai-tools/package.json b/packages/ai-tools/package.json index 49bdd7a8..ea28f66f 100644 --- a/packages/ai-tools/package.json +++ b/packages/ai-tools/package.json @@ -30,6 +30,7 @@ "dependencies": { "@datalust/winston-seq": "^2.0.0", "@inquirer/prompts": "^7.3.2", + "@keyv/sqlite": "^4.0.5", "@polymech/commons": "file:../commons", "@polymech/core": "file:../core", "@polymech/fs": "file:../fs", @@ -40,6 +41,8 @@ "glob": "^11.0.1", "inquirer": "^12.2.0", "jsdom": "^25.0.1", + "keyv": "^5.5.0", + "keyv-file": "^5.1.3", "marked": "^15.0.4", "mime-types": "^2.1.35", "nodemailer": "^6.9.16", diff --git a/packages/ai-tools/src/lib/tools/fs.ts b/packages/ai-tools/src/lib/tools/fs.ts index eae5f9c4..082689ea 100644 --- a/packages/ai-tools/src/lib/tools/fs.ts +++ b/packages/ai-tools/src/lib/tools/fs.ts @@ -98,7 +98,7 @@ const decodeContentSmart = (content: string, logger: any, identifier: string): s export const tools = (target: string, options: IKBotTask): Array => { const logger = toolLogger('fs', options) - const category = 'fs' + return [ { type: 'function', diff --git a/packages/ai-tools/src/lib/tools/keyv.ts b/packages/ai-tools/src/lib/tools/keyv.ts new file mode 100644 index 00000000..e8768e2c --- /dev/null +++ b/packages/ai-tools/src/lib/tools/keyv.ts @@ -0,0 +1,22 @@ +import * as path from 'path' +import Keyv from 'keyv' +import KeyvSqlite from '@keyv/sqlite' + +import { resolve } from '@polymech/commons' + +export const store = (storePath: string, ns: string = 'ns-unknown', opts: any = {}) => { + const keyvSqlite = new KeyvSqlite(path.resolve(resolve(storePath))) + return new Keyv({ store: keyvSqlite, ttl: 5000, namespace: ns, ...opts }) +} +export const get = async (key: string, storePath: string, ns: string = 'ns-unknown', opts: any = {}) => { + const keyv = store(storePath, ns, opts) + return await keyv.get(key) +} +export const set = async (key: string, value: any, storePath: string, ns: string = 'ns-unknown', opts: any = {}) => { + const keyv = store(storePath, ns, opts) + return await keyv.set(key, value) +} +export const list = async (key: string, value: any, storePath: string, ns: string = 'ns-unknown', opts: any = {}) => { + const keyv = store(storePath, ns, opts) + return await keyv.set(key, value) +} diff --git a/packages/ai-tools/src/lib/tools/memory.ts b/packages/ai-tools/src/lib/tools/memory.ts new file mode 100644 index 00000000..0e84b700 --- /dev/null +++ b/packages/ai-tools/src/lib/tools/memory.ts @@ -0,0 +1,379 @@ +import * as path from 'path' +import { RunnableToolFunction } from 'openai/lib/RunnableFunction' +import { isString } from '@polymech/core/primitives' + +import { toolLogger } from '../../index.js' +import { IKBotTask } from '../../types.js' + +import { store, get, set } from './keyv.js' + +// Helper function to get storage path +const getStoragePath = (options: IKBotTask): string => { + // For now, use default path. Later this can be configured via options + return path.join(process.cwd(), 'memory.sqlite'); +}; + +// Default collection name when none provided +const DEFAULT_COLLECTION = 'no-collection'; + +// Supported data formats +type DataFormat = 'text' | 'json' | 'binary'; + +// Memory entry structure +interface MemoryEntry { + value: string; + meta: { + type: DataFormat; + created: string; + updated: string; + }; +} + +// Helper function to process value based on format +const processValueForStorage = (value: string, format: DataFormat): string => { + switch (format) { + case 'json': + try { + // Validate JSON by parsing and re-stringifying + JSON.parse(value); + return value; + } catch (error) { + throw new Error('Invalid JSON format provided'); + } + case 'binary': + // For binary, we expect base64 encoded data + try { + // Validate base64 + Buffer.from(value, 'base64'); + return value; + } catch (error) { + throw new Error('Invalid base64 format for binary data'); + } + case 'text': + default: + return value; + } +}; + +// Helper function to create memory entry +const createMemoryEntry = (value: string, format: DataFormat): MemoryEntry => { + const now = new Date().toISOString(); + return { + value: processValueForStorage(value, format), + meta: { + type: format, + created: now, + updated: now + } + }; +}; + +export const tools = (target: string, options: IKBotTask): Array => { + const logger = toolLogger('memory', options) + const storagePath = getStoragePath(options); + + return [ + { + type: 'function', + function: { + name: 'memorize', + description: `Store information in memory as a key-value collection with format support. Supports text, JSON, and binary (base64) formats. + +Returns: { + success: boolean, + message: string, + meta: { + type: "text" | "json" | "binary", + created: string (ISO timestamp), + updated: string (ISO timestamp) + } +}`, + parameters: { + type: 'object', + properties: { + collection: { + type: 'string', + description: 'Collection name to organize related data (defaults to "no-collection" if not provided). Acts like a namespace.', + optional: true + }, + key: { + type: 'string', + description: 'Unique identifier for the data within the collection. Must be a string.' + }, + value: { + type: 'string', + description: 'The data to store. For format="text": any string. For format="json": valid JSON string. For format="binary": base64 encoded data.' + }, + format: { + type: 'string', + description: 'Data format type. "text" for plain text (default), "json" for JSON data (validates structure), "binary" for base64 encoded binary data.', + enum: ['text', 'json', 'binary'], + optional: true + } + }, + required: ['key', 'value'] + }, + function: async (params: any) => { + try { + const { collection = DEFAULT_COLLECTION, key, value, format = 'text' } = params; + logger.debug(`Tool::Memorize Storing ${key} in collection ${collection} as ${format}`); + + const memoryEntry = createMemoryEntry(value, format as DataFormat); + await set(`${collection}:${key}`, memoryEntry, storagePath, collection); + + return { + success: true, + message: `Stored ${key} in collection ${collection} as ${format}`, + meta: memoryEntry.meta + }; + } catch (error) { + logger.error('Error storing memory', error); + return { + success: false, + message: error instanceof Error ? error.message : 'Unknown error occurred' + }; + } + }, + parse: JSON.parse + } + } as RunnableToolFunction, + { + type: 'function', + function: { + name: 'recall', + description: `Retrieve stored information from memory by collection and key, including format metadata. + +Returns: { + success: boolean, + value?: string (the stored data), + meta?: { + type: "text" | "json" | "binary", + created: string (ISO timestamp), + updated: string (ISO timestamp) + }, + key: string, + collection: string, + message?: string (error message if success=false) +}`, + parameters: { + type: 'object', + properties: { + collection: { + type: 'string', + description: 'Collection name to retrieve from (defaults to "no-collection" if not provided). Must match the collection used when storing.', + optional: true + }, + key: { + type: 'string', + description: 'The unique identifier of the data to retrieve. Must match the key used when storing.' + } + }, + required: ['key'] + }, + function: async (params: any) => { + try { + const { collection = DEFAULT_COLLECTION, key } = params; + logger.debug(`Tool::Recall Retrieving ${key} from collection ${collection}`); + + const storedData = await get(`${collection}:${key}`, storagePath, collection); + if (storedData === undefined) { + return { success: false, message: `Key ${key} not found in collection ${collection}` }; + } + + // Handle both old format (plain string) and new format (MemoryEntry) + let memoryEntry: MemoryEntry; + if (typeof storedData === 'string') { + // Legacy format - convert to new format + memoryEntry = { + value: storedData, + meta: { + type: 'text', + created: new Date().toISOString(), + updated: new Date().toISOString() + } + }; + } else { + memoryEntry = storedData as MemoryEntry; + } + + return { + success: true, + value: memoryEntry.value, + meta: memoryEntry.meta, + key, + collection + }; + } catch (error) { + logger.error('Error retrieving memory', error); + return { + success: false, + message: error instanceof Error ? error.message : 'Unknown error occurred' + }; + } + }, + parse: JSON.parse + } + } as RunnableToolFunction, + { + type: 'function', + function: { + name: 'forget', + description: `Remove a specific key from memory collection. + +Returns: { + success: boolean, + message: string (confirmation or error message) +}`, + parameters: { + type: 'object', + properties: { + collection: { + type: 'string', + description: 'Collection name to remove from (defaults to "no-collection" if not provided). Must match the collection where the key was stored.', + optional: true + }, + key: { + type: 'string', + description: 'The unique identifier of the data to remove. Must match exactly the key used when storing.' + } + }, + required: ['key'] + }, + function: async (params: any) => { + try { + const { collection = DEFAULT_COLLECTION, key } = params; + logger.debug(`Tool::Forget Removing ${key} from collection ${collection}`); + + const keyv = store(storagePath, collection); + const deleted = await keyv.delete(`${collection}:${key}`); + return { success: deleted, message: deleted ? `Removed ${key} from ${collection}` : `Key ${key} not found in ${collection}` }; + } catch (error) { + logger.error('Error removing from memory', error); + return { + success: false, + message: error instanceof Error ? error.message : 'Unknown error occurred' + }; + } + }, + parse: JSON.parse + } + } as RunnableToolFunction, + { + type: 'function', + function: { + name: 'list_memories', + description: `List all keys in a specific collection using Keyv's iterator method. + +Returns: { + success: boolean, + collection: string (the collection name), + keys: string[] (array of key names in the collection), + entries: Array<{ + key: string, + meta?: { + type: "text" | "json" | "binary", + created: string (ISO timestamp), + updated: string (ISO timestamp) + } + }>, + count: number (total number of keys), + message?: string (info or error message) +}`, + parameters: { + type: 'object', + properties: { + collection: { + type: 'string', + description: 'Collection name to list keys from (defaults to "no-collection" if not provided). Will return all keys stored in this collection namespace.', + optional: true + } + }, + required: [] + }, + function: async (params: any) => { + try { + const { collection = DEFAULT_COLLECTION } = params; + + logger.debug(`Tool::ListMemories Listing keys in collection ${collection}`); + + // Create a Keyv instance for the specific collection to use iterator + const keyv = store(storagePath, collection); + const keys: string[] = []; + const entries: { key: string; meta?: any }[] = []; + + try { + // Check if iterator method exists and use it + if (typeof keyv.iterator === 'function') { + try { + // Try calling iterator without arguments first + const iterator = (keyv as any).iterator(); + for await (const [key, value] of iterator) { + // Remove the collection prefix from the key to get the clean key name + const cleanKey = key.replace(`${collection}:`, ''); + keys.push(cleanKey); + + // Try to extract metadata if it's a MemoryEntry + let meta = undefined; + if (value && typeof value === 'object' && value.meta) { + meta = value.meta; + } + + entries.push({ key: cleanKey, meta }); + } + } catch (iteratorCallError) { + logger.warn(`Tool::ListMemories Iterator call failed:`, iteratorCallError); + // Fall through to the not available case + return { + success: true, + collection, + keys: [], + entries: [], + count: 0, + message: 'Iterator call failed. Unable to list keys.' + }; + } + } else { + // Iterator not available, provide helpful message + logger.warn(`Tool::ListMemories Iterator method not available for Keyv instance`); + return { + success: true, + collection, + keys: [], + entries: [], + count: 0, + message: 'Iterator method not available in this Keyv version. Use individual key operations instead.' + }; + } + + return { + success: true, + collection, + keys, + entries, + count: keys.length + }; + } catch (iteratorError) { + // If iterator fails, fall back to returning basic info + logger.warn(`Tool::ListMemories Iterator failed for collection ${collection}:`, iteratorError); + return { + success: true, + collection, + keys: [], + entries: [], + count: 0, + message: 'Iterator failed or collection is empty' + }; + } + } catch (error) { + logger.error('Error listing memories', error); + return { + success: false, + message: error instanceof Error ? error.message : 'Unknown error occurred' + }; + } + }, + parse: JSON.parse + } + } as RunnableToolFunction + ] +}; diff --git a/packages/ai-tools/src/lib/tools/tools.ts b/packages/ai-tools/src/lib/tools/tools.ts index 4498fd3d..46a1701a 100644 --- a/packages/ai-tools/src/lib/tools/tools.ts +++ b/packages/ai-tools/src/lib/tools/tools.ts @@ -6,6 +6,7 @@ import { tools as interactTools } from './interact.js' import { tools as userTools } from './user.js' import { tools as search } from './search.js' import { tools as webTools } from './web.js' +import { tools as memoryTools } from './memory.js' //import { tools as emailTools } from './email' export const tools = { @@ -17,5 +18,6 @@ export const tools = { user: userTools, search: search, web: webTools, + memory: memoryTools, // email: emailTools } diff --git a/packages/ai-tools/src/types_kbot.ts b/packages/ai-tools/src/types_kbot.ts index 99a7db72..897e6b73 100644 --- a/packages/ai-tools/src/types_kbot.ts +++ b/packages/ai-tools/src/types_kbot.ts @@ -8,7 +8,7 @@ export interface IKBotOptions { /** Optional destination path for the result, will substitute ${MODEL_NAME} and ${ROUTER} in the path. Optional, used for "completion" mode */ dst?: string | undefined; /** How to handle output if --dst file already exists: "concat" (append) or "merge" (try to merge structures if possible, otherwise append). Only used if --dst is specified. */ - append?: ("concat" | "merge") | undefined; + append?: ("concat" | "merge" | "replace") | undefined; /** Specify how to wrap the output, "meta (file name, absolute path, cwd)" or "none". */ wrap?: "meta" | "none"; /** Iterate over items, supported: GLOB | Path to JSON File | array of strings (comma separated). To test different models, use --each="gpt-3.5-turbo,gpt-4o", the actual string will exposed as variable `ITEM`, eg: --dst="${ITEM}-output.md" */ @@ -31,8 +31,6 @@ export interface IKBotOptions {   OpenRouter models:  - 01-ai/yi-large | paid - aetherwiing/mn-starcannon-12b | paid agentica-org/deepcoder-14b-preview | paid agentica-org/deepcoder-14b-preview:free | free ai21/jamba-1.6-large | paid @@ -48,11 +46,8 @@ export interface IKBotOptions { anthropic/claude-3-haiku:beta | paid anthropic/claude-3-opus | paid anthropic/claude-3-opus:beta | paid - anthropic/claude-3-sonnet | paid - anthropic/claude-3-sonnet:beta | paid anthropic/claude-3.5-haiku | paid anthropic/claude-3.5-haiku-20241022 | paid - anthropic/claude-3.5-haiku-20241022:beta | paid anthropic/claude-3.5-haiku:beta | paid anthropic/claude-3.5-sonnet | paid anthropic/claude-3.5-sonnet-20240620 | paid @@ -62,23 +57,17 @@ export interface IKBotOptions { anthropic/claude-3.7-sonnet:beta | paid anthropic/claude-3.7-sonnet:thinking | paid anthropic/claude-opus-4 | paid + anthropic/claude-opus-4.1 | paid anthropic/claude-sonnet-4 | paid - anthropic/claude-2 | paid - anthropic/claude-2:beta | paid - anthropic/claude-2.0 | paid - anthropic/claude-2.0:beta | paid - anthropic/claude-2.1 | paid - anthropic/claude-2.1:beta | paid - arcee-ai/arcee-blitz | paid - arcee-ai/caller-large | paid arcee-ai/coder-large | paid arcee-ai/maestro-reasoning | paid arcee-ai/spotlight | paid arcee-ai/virtuoso-large | paid - arcee-ai/virtuoso-medium-v2 | paid + arliai/qwq-32b-arliai-rpr-v1 | paid arliai/qwq-32b-arliai-rpr-v1:free | free openrouter/auto | paid baidu/ernie-4.5-300b-a47b | paid + bytedance/ui-tars-1.5-7b | paid cohere/command | paid cohere/command-a | paid cohere/command-r | paid @@ -92,10 +81,9 @@ export interface IKBotOptions { deepseek/deepseek-r1-0528-qwen3-8b | paid deepseek/deepseek-r1-0528-qwen3-8b:free | free deepseek/deepseek-chat | paid - deepseek/deepseek-chat:free | free deepseek/deepseek-chat-v3-0324 | paid deepseek/deepseek-chat-v3-0324:free | free - deepseek/deepseek-v3-base:free | free + deepseek/deepseek-v3-base | paid deepseek/deepseek-r1 | paid deepseek/deepseek-r1:free | free deepseek/deepseek-r1-0528 | paid @@ -109,12 +97,11 @@ export interface IKBotOptions { deepseek/deepseek-r1-distill-qwen-32b | paid deepseek/deepseek-r1-distill-qwen-7b | paid cognitivecomputations/dolphin-mixtral-8x22b | paid + cognitivecomputations/dolphin3.0-mistral-24b | paid cognitivecomputations/dolphin3.0-mistral-24b:free | free cognitivecomputations/dolphin3.0-r1-mistral-24b | paid cognitivecomputations/dolphin3.0-r1-mistral-24b:free | free eleutherai/llemma_7b | paid - eva-unit-01/eva-llama-3.33-70b | paid - eva-unit-01/eva-qwen-2.5-72b | paid sao10k/fimbulvetr-11b-v2 | paid alpindale/goliath-120b | paid google/gemini-flash-1.5 | paid @@ -124,6 +111,7 @@ export interface IKBotOptions { google/gemini-2.0-flash-exp:free | free google/gemini-2.0-flash-lite-001 | paid google/gemini-2.5-flash | paid + google/gemini-2.5-flash-lite | paid google/gemini-2.5-flash-lite-preview-06-17 | paid google/gemini-2.5-pro | paid google/gemini-2.5-pro-exp-03-25 | paid @@ -141,6 +129,7 @@ export interface IKBotOptions { google/gemma-3n-e2b-it:free | free google/gemma-3n-e4b-it | paid google/gemma-3n-e4b-it:free | free + openrouter/horizon-beta | paid inception/mercury | paid inception/mercury-coder | paid infermatic/mn-inferor-12b | paid @@ -151,7 +140,6 @@ export interface IKBotOptions { liquid/lfm-40b | paid liquid/lfm-7b | paid meta-llama/llama-guard-3-8b | paid - alpindale/magnum-72b | paid anthracite-org/magnum-v2-72b | paid anthracite-org/magnum-v4-72b | paid mancer/weaver | paid @@ -174,6 +162,7 @@ export interface IKBotOptions { meta-llama/llama-4-scout | paid meta-llama/llama-guard-4-12b | paid meta-llama/llama-guard-2-8b | paid + microsoft/mai-ds-r1 | paid microsoft/mai-ds-r1:free | free microsoft/phi-4 | paid microsoft/phi-4-multimodal-instruct | paid @@ -187,10 +176,10 @@ export interface IKBotOptions { mistralai/mistral-large | paid mistralai/mistral-large-2407 | paid mistralai/mistral-large-2411 | paid - nothingiisreal/mn-celeste-12b | paid mistralai/mistral-small | paid mistralai/mistral-tiny | paid mistralai/codestral-2501 | paid + mistralai/codestral-2508 | paid mistralai/devstral-medium | paid mistralai/devstral-small | paid mistralai/devstral-small-2505 | paid @@ -219,10 +208,10 @@ export interface IKBotOptions { mistralai/pixtral-12b | paid mistralai/pixtral-large-2411 | paid mistralai/mistral-saba | paid + moonshotai/kimi-vl-a3b-thinking | paid moonshotai/kimi-vl-a3b-thinking:free | free moonshotai/kimi-k2 | paid moonshotai/kimi-k2:free | free - morph/morph-v2 | paid morph/morph-v3-fast | paid morph/morph-v3-large | paid gryphe/mythomax-l2-13b | paid @@ -230,6 +219,7 @@ export interface IKBotOptions { neversleep/llama-3.1-lumimaid-8b | paid neversleep/noromaid-20b | paid nousresearch/deephermes-3-llama-3-8b-preview:free | free + nousresearch/deephermes-3-mistral-24b-preview | paid nousresearch/nous-hermes-2-mixtral-8x7b-dpo | paid nousresearch/hermes-3-llama-3.1-405b | paid nousresearch/hermes-3-llama-3.1-70b | paid @@ -240,6 +230,8 @@ export interface IKBotOptions { nvidia/llama-3.3-nemotron-super-49b-v1 | paid openai/chatgpt-4o-latest | paid openai/codex-mini | paid + openai/gpt-oss-120b | paid + openai/gpt-oss-20b | paid openai/gpt-3.5-turbo | paid openai/gpt-3.5-turbo-0613 | paid openai/gpt-3.5-turbo-16k | paid @@ -264,8 +256,6 @@ export interface IKBotOptions { openai/o1 | paid openai/o1-mini | paid openai/o1-mini-2024-09-12 | paid - openai/o1-preview | paid - openai/o1-preview-2024-09-12 | paid openai/o1-pro | paid openai/o3 | paid openai/o3-mini | paid @@ -281,6 +271,7 @@ export interface IKBotOptions { perplexity/sonar-reasoning | paid perplexity/sonar-reasoning-pro | paid pygmalionai/mythalion-13b | paid + featherless/qwerky-72b:free | free qwen/qwen-2-72b-instruct | paid qwen/qwen-vl-max | paid qwen/qwen-vl-plus | paid @@ -296,13 +287,16 @@ export interface IKBotOptions { qwen/qwen3-14b:free | free qwen/qwen3-235b-a22b | paid qwen/qwen3-235b-a22b:free | free + qwen/qwen3-235b-a22b-2507 | paid + qwen/qwen3-235b-a22b-thinking-2507 | paid qwen/qwen3-30b-a3b | paid qwen/qwen3-30b-a3b:free | free + qwen/qwen3-30b-a3b-instruct-2507 | paid qwen/qwen3-32b | paid - qwen/qwen3-32b:free | free qwen/qwen3-4b:free | free qwen/qwen3-8b | paid qwen/qwen3-8b:free | free + qwen/qwen3-coder | paid qwen/qwq-32b | paid qwen/qwq-32b:free | free qwen/qwq-32b-preview | paid @@ -311,16 +305,14 @@ export interface IKBotOptions { qwen/qwen-2.5-7b-instruct | paid qwen/qwen-2.5-coder-32b-instruct | paid qwen/qwen-2.5-coder-32b-instruct:free | free - featherless/qwerky-72b:free | free - rekaai/reka-flash-3 | paid rekaai/reka-flash-3:free | free undi95/remm-slerp-l2-13b | paid sao10k/l3-lunaris-8b | paid sao10k/l3-euryale-70b | paid sao10k/l3.1-euryale-70b | paid sao10k/l3.3-euryale-70b | paid - sarvamai/sarvam-m | paid sarvamai/sarvam-m:free | free + shisa-ai/shisa-v2-llama3.3-70b | paid shisa-ai/shisa-v2-llama3.3-70b:free | free raifle/sorcererlm-8x22b | paid switchpoint/router | paid @@ -333,9 +325,9 @@ export interface IKBotOptions { thedrummer/unslopnemo-12b | paid thedrummer/valkyrie-49b-v1 | paid thudm/glm-4-32b | paid - thudm/glm-4-32b:free | free thudm/glm-4.1v-9b-thinking | paid thudm/glm-z1-32b:free | free + tngtech/deepseek-r1t-chimera | paid tngtech/deepseek-r1t-chimera:free | free tngtech/deepseek-r1t2-chimera:free | free undi95/toppy-m-7b | paid @@ -350,6 +342,10 @@ export interface IKBotOptions { x-ai/grok-3-mini-beta | paid x-ai/grok-4 | paid x-ai/grok-vision-beta | paid + z-ai/glm-4-32b | paid + z-ai/glm-4.5 | paid + z-ai/glm-4.5-air | paid + z-ai/glm-4.5-air:free | free   OpenAI models:  @@ -408,8 +404,6 @@ export interface IKBotOptions { o1-2024-12-17 o1-mini o1-mini-2024-09-12 - o1-preview - o1-preview-2024-09-12 o1-pro o1-pro-2025-03-19 o3-mini diff --git a/packages/kbot/scripts/ollama/oai-20b.sh b/packages/kbot/scripts/ollama/oai-20b.sh new file mode 100644 index 00000000..e1ab45de --- /dev/null +++ b/packages/kbot/scripts/ollama/oai-20b.sh @@ -0,0 +1,2 @@ +ollama pull gpt-oss:20b +ollama run gpt-oss:20b diff --git a/packages/kbot/scripts/ollama/test-oai-20b.sh b/packages/kbot/scripts/ollama/test-oai-20b.sh new file mode 100644 index 00000000..9c2bdd77 --- /dev/null +++ b/packages/kbot/scripts/ollama/test-oai-20b.sh @@ -0,0 +1,11 @@ +kbot-d.cmd --router=ollama \ +--model=gpt-oss:20b \ +--mode=completion \ +--baseURL=http://localhost:11434/v1 \ +--prompt=./tools.md \ +--preferences=none \ +--filters=code \ +--dst=./tools-test-ouput.md + + + diff --git a/packages/kbot/scripts/ollama/tools.md b/packages/kbot/scripts/ollama/tools.md new file mode 100644 index 00000000..43af98a6 --- /dev/null +++ b/packages/kbot/scripts/ollama/tools.md @@ -0,0 +1 @@ +meaning of love, per continent - as markdown \ No newline at end of file diff --git a/packages/media/dist-in/commands/background-remove.d.ts b/packages/media/dist-in/commands/background-remove.d.ts new file mode 100644 index 00000000..0e1386be --- /dev/null +++ b/packages/media/dist-in/commands/background-remove.d.ts @@ -0,0 +1,6 @@ +import * as CLI from 'yargs'; +export declare const defaultOptions: (yargs: CLI.Argv) => any; +export declare const command = "background:remove"; +export declare const desc = "Remove background from images using AI"; +export declare const builder: (yargs: CLI.Argv) => any; +export declare function handler(argv: CLI.Arguments): Promise; diff --git a/packages/media/dist-in/commands/background-remove.js b/packages/media/dist-in/commands/background-remove.js new file mode 100644 index 00000000..e38e6041 --- /dev/null +++ b/packages/media/dist-in/commands/background-remove.js @@ -0,0 +1,86 @@ +import { CONFIG_DEFAULT } from '@polymech/commons'; +import { logger } from '../index.js'; +import { cli } from '../cli.js'; +import { sanitize, defaults } from '../_cli.js'; +import { backgroundRemove } from '../lib/media/images/background-remove.js'; +export const defaultOptions = (yargs) => { + return yargs.option('src', { + describe: 'FILE|FOLDER|GLOB', + demandOption: true + }).option('dst', { + describe: 'FILE|FOLDER|GLOB' + }).option('debug', { + default: false, + describe: 'Enable internal debug messages', + type: 'boolean' + }).option('alt', { + default: false, + describe: 'Use alternate tokenizer, & instead of $', + type: 'boolean' + }).option('dry', { + default: false, + describe: 'Run without conversion', + type: 'boolean' + }).option('verbose', { + default: false, + describe: 'Show internal messages', + type: 'boolean' + }).option('logLevel', { + describe: 'Log level : warn, info, debug, error', + type: 'string', + default: 'info' + }).option('apiKey', { + describe: 'Replicate API key (or set REPLICATE_API_TOKEN env var)', + type: 'string' + }).option('model', { + describe: 'Background removal model to use', + choices: ['u2net', 'u2netp', 'u2net_human_seg', 'u2net_cloth_seg', 'silueta'], + default: 'u2net' + }).option('alphaMattting', { + describe: 'Enable alpha matting for better edge refinement', + type: 'boolean', + default: false + }).option('alphaMattingForegroundThreshold', { + describe: 'Alpha matting foreground threshold', + type: 'number', + default: 270 + }).option('alphaMattingBackgroundThreshold', { + describe: 'Alpha matting background threshold', + type: 'number', + default: 10 + }).option('alphaMattingErodeSize', { + describe: 'Alpha matting erode size', + type: 'number', + default: 10 + }); +}; +export const command = 'background:remove'; +export const desc = 'Remove background from images using AI'; +export const builder = defaultOptions; +export async function handler(argv) { + defaults(); + const options = sanitize(argv); + logger.settings.minLevel = options.logLevel; + const config = CONFIG_DEFAULT(); + // Get API key from argument or environment variable + options.apiKey = options.apiKey || process.env.REPLICATE_API_TOKEN || config?.replicate?.key; + if (!options.apiKey) { + logger.error('Replicate API key is required. Provide it via --apiKey argument or set REPLICATE_API_TOKEN environment variable'); + logger.info('Get your API key at: https://replicate.com/account/api-tokens'); + process.exit(1); + } + // Map CLI arguments to library options + options.model = argv.model; + options.alpha_matting = argv.alphaMattting; + options.alpha_matting_foreground_threshold = argv.alphaMattingForegroundThreshold; + options.alpha_matting_background_threshold = argv.alphaMattingBackgroundThreshold; + options.alpha_matting_erode_size = argv.alphaMattingErodeSize; + logger.info("Removing background with options:", { + model: options.model, + alpha_matting: options.alpha_matting, + files: options.srcInfo?.FILES?.length || 0 + }); + await backgroundRemove(options); +} +cli.command(command, desc, builder, handler); +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmFja2dyb3VuZC1yZW1vdmUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvY29tbWFuZHMvYmFja2dyb3VuZC1yZW1vdmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLG1CQUFtQixDQUFBO0FBQ2xELE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxhQUFhLENBQUE7QUFDcEMsT0FBTyxFQUFFLEdBQUcsRUFBRSxNQUFNLFdBQVcsQ0FBQTtBQUMvQixPQUFPLEVBQ0gsUUFBUSxFQUNSLFFBQVEsRUFDWCxNQUFNLFlBQVksQ0FBQTtBQUVuQixPQUFPLEVBQ0gsZ0JBQWdCLEVBRW5CLE1BQU0sMENBQTBDLENBQUE7QUFFakQsTUFBTSxDQUFDLE1BQU0sY0FBYyxHQUFHLENBQUMsS0FBZSxFQUFFLEVBQUU7SUFDOUMsT0FBTyxLQUFLLENBQUMsTUFBTSxDQUFDLEtBQUssRUFBRTtRQUN2QixRQUFRLEVBQUUsa0JBQWtCO1FBQzVCLFlBQVksRUFBRSxJQUFJO0tBQ3JCLENBQUMsQ0FBQyxNQUFNLENBQUMsS0FBSyxFQUFFO1FBQ2IsUUFBUSxFQUFFLGtCQUFrQjtLQUMvQixDQUFDLENBQUMsTUFBTSxDQUFDLE9BQU8sRUFBRTtRQUNmLE9BQU8sRUFBRSxLQUFLO1FBQ2QsUUFBUSxFQUFFLGdDQUFnQztRQUMxQyxJQUFJLEVBQUUsU0FBUztLQUNsQixDQUFDLENBQUMsTUFBTSxDQUFDLEtBQUssRUFBRTtRQUNiLE9BQU8sRUFBRSxLQUFLO1FBQ2QsUUFBUSxFQUFFLHlDQUF5QztRQUNuRCxJQUFJLEVBQUUsU0FBUztLQUNsQixDQUFDLENBQUMsTUFBTSxDQUFDLEtBQUssRUFBRTtRQUNiLE9BQU8sRUFBRSxLQUFLO1FBQ2QsUUFBUSxFQUFFLHdCQUF3QjtRQUNsQyxJQUFJLEVBQUUsU0FBUztLQUNsQixDQUFDLENBQUMsTUFBTSxDQUFDLFNBQVMsRUFBRTtRQUNqQixPQUFPLEVBQUUsS0FBSztRQUNkLFFBQVEsRUFBRSx3QkFBd0I7UUFDbEMsSUFBSSxFQUFFLFNBQVM7S0FDbEIsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxVQUFVLEVBQUU7UUFDbEIsUUFBUSxFQUFFLHNDQUFzQztRQUNoRCxJQUFJLEVBQUUsUUFBUTtRQUNkLE9BQU8sRUFBRSxNQUFNO0tBQ2xCLENBQUMsQ0FBQyxNQUFNLENBQUMsUUFBUSxFQUFFO1FBQ2hCLFFBQVEsRUFBRSx3REFBd0Q7UUFDbEUsSUFBSSxFQUFFLFFBQVE7S0FDakIsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxPQUFPLEVBQUU7UUFDZixRQUFRLEVBQUUsaUNBQWlDO1FBQzNDLE9BQU8sRUFBRSxDQUFDLE9BQU8sRUFBRSxRQUFRLEVBQUUsaUJBQWlCLEVBQUUsaUJBQWlCLEVBQUUsU0FBUyxDQUFDO1FBQzdFLE9BQU8sRUFBRSxPQUFPO0tBQ25CLENBQUMsQ0FBQyxNQUFNLENBQUMsZUFBZSxFQUFFO1FBQ3ZCLFFBQVEsRUFBRSxpREFBaUQ7UUFDM0QsSUFBSSxFQUFFLFNBQVM7UUFDZixPQUFPLEVBQUUsS0FBSztLQUNqQixDQUFDLENBQUMsTUFBTSxDQUFDLGlDQUFpQyxFQUFFO1FBQ3pDLFFBQVEsRUFBRSxvQ0FBb0M7UUFDOUMsSUFBSSxFQUFFLFFBQVE7UUFDZCxPQUFPLEVBQUUsR0FBRztLQUNmLENBQUMsQ0FBQyxNQUFNLENBQUMsaUNBQWlDLEVBQUU7UUFDekMsUUFBUSxFQUFFLG9DQUFvQztRQUM5QyxJQUFJLEVBQUUsUUFBUTtRQUNkLE9BQU8sRUFBRSxFQUFFO0tBQ2QsQ0FBQyxDQUFDLE1BQU0sQ0FBQyx1QkFBdUIsRUFBRTtRQUMvQixRQUFRLEVBQUUsMEJBQTBCO1FBQ3BDLElBQUksRUFBRSxRQUFRO1FBQ2QsT0FBTyxFQUFFLEVBQUU7S0FDZCxDQUFDLENBQUE7QUFDTixDQUFDLENBQUE7QUFFRCxNQUFNLENBQUMsTUFBTSxPQUFPLEdBQUcsbUJBQW1CLENBQUM7QUFDM0MsTUFBTSxDQUFDLE1BQU0sSUFBSSxHQUFHLHdDQUF3QyxDQUFDO0FBQzdELE1BQU0sQ0FBQyxNQUFNLE9BQU8sR0FBRyxjQUFjLENBQUM7QUFFdEMsTUFBTSxDQUFDLEtBQUssVUFBVSxPQUFPLENBQUMsSUFBbUI7SUFDN0MsUUFBUSxFQUFFLENBQUE7SUFDVixNQUFNLE9BQU8sR0FBRyxRQUFRLENBQUMsSUFBSSxDQUE0QixDQUFBO0lBQ3pELE1BQU0sQ0FBQyxRQUFRLENBQUMsUUFBUSxHQUFHLE9BQU8sQ0FBQyxRQUFlLENBQUE7SUFDbEQsTUFBTSxNQUFNLEdBQVEsY0FBYyxFQUFFLENBQUE7SUFFcEMsb0RBQW9EO0lBQ3BELE9BQU8sQ0FBQyxNQUFNLEdBQUcsT0FBTyxDQUFDLE1BQU0sSUFBSSxPQUFPLENBQUMsR0FBRyxDQUFDLG1CQUFtQixJQUFJLE1BQU0sRUFBRSxTQUFTLEVBQUUsR0FBRyxDQUFDO0lBRTdGLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxFQUFFLENBQUM7UUFDbEIsTUFBTSxDQUFDLEtBQUssQ0FBQyxpSEFBaUgsQ0FBQyxDQUFDO1FBQ2hJLE1BQU0sQ0FBQyxJQUFJLENBQUMsK0RBQStELENBQUMsQ0FBQztRQUM3RSxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3BCLENBQUM7SUFFRCx1Q0FBdUM7SUFDdkMsT0FBTyxDQUFDLEtBQUssR0FBRyxJQUFJLENBQUMsS0FBZSxDQUFDO0lBQ3JDLE9BQU8sQ0FBQyxhQUFhLEdBQUcsSUFBSSxDQUFDLGFBQXdCLENBQUM7SUFDdEQsT0FBTyxDQUFDLGtDQUFrQyxHQUFHLElBQUksQ0FBQywrQkFBeUMsQ0FBQztJQUM1RixPQUFPLENBQUMsa0NBQWtDLEdBQUcsSUFBSSxDQUFDLCtCQUF5QyxDQUFDO0lBQzVGLE9BQU8sQ0FBQyx3QkFBd0IsR0FBRyxJQUFJLENBQUMscUJBQStCLENBQUM7SUFFeEUsTUFBTSxDQUFDLElBQUksQ0FBQyxtQ0FBbUMsRUFBRTtRQUM3QyxLQUFLLEVBQUUsT0FBTyxDQUFDLEtBQUs7UUFDcEIsYUFBYSxFQUFFLE9BQU8sQ0FBQyxhQUFhO1FBQ3BDLEtBQUssRUFBRSxPQUFPLENBQUMsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLElBQUksQ0FBQztLQUM3QyxDQUFDLENBQUM7SUFFSCxNQUFNLGdCQUFnQixDQUFDLE9BQU8sQ0FBQyxDQUFDO0FBQ3BDLENBQUM7QUFFRCxHQUFHLENBQUMsT0FBTyxDQUFDLE9BQU8sRUFBRSxJQUFJLEVBQUUsT0FBTyxFQUFFLE9BQU8sQ0FBQyxDQUFBIn0= \ No newline at end of file diff --git a/packages/media/dist-in/commands/resize.d.ts b/packages/media/dist-in/commands/resize.d.ts index 3298fb71..83c34a01 100644 --- a/packages/media/dist-in/commands/resize.d.ts +++ b/packages/media/dist-in/commands/resize.d.ts @@ -1,3 +1,6 @@ import * as CLI from 'yargs'; export declare const defaultOptions: (yargs: CLI.Argv) => any; -export declare const register: (cli: CLI.Argv) => any; +export declare const command = "resize"; +export declare const desc = "Resizes files"; +export declare const builder: (yargs: CLI.Argv) => any; +export declare function handler(argv: CLI.Arguments): Promise; diff --git a/packages/media/dist-in/commands/resize.js b/packages/media/dist-in/commands/resize.js index a6b1bc23..6c1f6fab 100644 --- a/packages/media/dist-in/commands/resize.js +++ b/packages/media/dist-in/commands/resize.js @@ -1,5 +1,6 @@ import { logger } from '../index.js'; import { resize } from '../lib/media/images/resize.js'; +import { cli } from '../cli.js'; import { sanitize, defaults } from '../_cli.js'; export const defaultOptions = (yargs) => { return yargs.option('src', { @@ -51,14 +52,15 @@ export const defaultOptions = (yargs) => { default: 'info' }); }; -let options = (yargs) => defaultOptions(yargs); -export const register = (cli) => { - return cli.command('resize', 'Resizes files', options, async (argv) => { - defaults(); - const options = sanitize(argv); - logger.settings.minLevel = options.logLevel; - logger.info("options " + argv.dst, options); - await resize(options); - }); -}; -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVzaXplLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NvbW1hbmRzL3Jlc2l6ZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFDQSxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sYUFBYSxDQUFBO0FBQ3BDLE9BQU8sRUFDSCxNQUFNLEVBQ1QsTUFBTSwrQkFBK0IsQ0FBQTtBQUV0QyxPQUFPLEVBQ0gsUUFBUSxFQUNSLFFBQVEsRUFDWCxNQUFNLFlBQVksQ0FBQTtBQU1uQixNQUFNLENBQUMsTUFBTSxjQUFjLEdBQUcsQ0FBQyxLQUFlLEVBQUUsRUFBRTtJQUM5QyxPQUFPLEtBQUssQ0FBQyxNQUFNLENBQUMsS0FBSyxFQUFFO1FBQ3ZCLFFBQVEsRUFBRSxrQkFBa0I7UUFDNUIsWUFBWSxFQUFFLElBQUk7S0FDckIsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxLQUFLLEVBQUU7UUFDYixRQUFRLEVBQUUsa0JBQWtCO0tBQy9CLENBQUMsQ0FBQyxNQUFNLENBQUMsT0FBTyxFQUFFO1FBQ2YsT0FBTyxFQUFFLEtBQUs7UUFDZCxRQUFRLEVBQUUsZ0NBQWdDO1FBQzFDLElBQUksRUFBRSxTQUFTO0tBQ2xCLENBQUMsQ0FBQyxNQUFNLENBQUMsS0FBSyxFQUFFO1FBQ2IsT0FBTyxFQUFFLEtBQUs7UUFDZCxRQUFRLEVBQUUseUNBQXlDO1FBQ25ELElBQUksRUFBRSxTQUFTO0tBQ2xCLENBQUMsQ0FBQyxNQUFNLENBQUMsS0FBSyxFQUFFO1FBQ2IsT0FBTyxFQUFFLEtBQUs7UUFDZCxRQUFRLEVBQUUsd0JBQXdCO1FBQ2xDLElBQUksRUFBRSxTQUFTO0tBQ2xCLENBQUMsQ0FBQyxNQUFNLENBQUMsU0FBUyxFQUFFO1FBQ2pCLE9BQU8sRUFBRSxLQUFLO1FBQ2QsUUFBUSxFQUFFLHdCQUF3QjtRQUNsQyxJQUFJLEVBQUUsU0FBUztLQUNsQixDQUFDLENBQUMsTUFBTSxDQUFDLFNBQVMsRUFBRTtRQUNqQixPQUFPLEVBQUUsS0FBSztRQUNkLFFBQVEsRUFBRSwyQkFBMkI7UUFDckMsSUFBSSxFQUFFLFFBQVE7S0FDakIsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxPQUFPLEVBQUU7UUFDZixRQUFRLEVBQUUsbUJBQW1CO1FBQzdCLElBQUksRUFBRSxRQUFRO0tBQ2pCLENBQUMsQ0FBQyxNQUFNLENBQUMsUUFBUSxFQUFFO1FBQ2hCLFFBQVEsRUFBRSxxQkFBcUI7UUFDL0IsSUFBSSxFQUFFLFFBQVE7S0FDakIsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxXQUFXLEVBQUU7UUFDbkIsUUFBUSxFQUFFLDZCQUE2QjtRQUN2QyxJQUFJLEVBQUUsUUFBUTtLQUNqQixDQUFDLENBQUMsTUFBTSxDQUFDLFVBQVUsRUFBRTtRQUNsQixRQUFRLEVBQUUsNEJBQTRCO1FBQ3RDLElBQUksRUFBRSxRQUFRO0tBQ2pCLENBQUMsQ0FBQyxNQUFNLENBQUMsU0FBUyxFQUFFO1FBQ2pCLFFBQVEsRUFBRSwyQkFBMkI7UUFDckMsSUFBSSxFQUFFLFFBQVE7S0FDakIsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxTQUFTLEVBQUU7UUFDakIsUUFBUSxFQUFFLGlDQUFpQztRQUMzQyxJQUFJLEVBQUUsUUFBUTtLQUNqQixDQUFDLENBQUMsTUFBTSxDQUFDLFVBQVUsRUFBRTtRQUNsQixRQUFRLEVBQUUsc0NBQXNDO1FBQ2hELElBQUksRUFBRSxRQUFRO1FBQ2QsT0FBTyxFQUFFLE1BQU07S0FDbEIsQ0FBQyxDQUFBO0FBQ04sQ0FBQyxDQUFBO0FBRUQsSUFBSSxPQUFPLEdBQUcsQ0FBQyxLQUFlLEVBQUUsRUFBRSxDQUFDLGNBQWMsQ0FBQyxLQUFLLENBQUMsQ0FBQTtBQUV4RCxNQUFNLENBQUMsTUFBTSxRQUFRLEdBQUcsQ0FBQyxHQUFhLEVBQUUsRUFBRTtJQUN0QyxPQUFPLEdBQUcsQ0FBQyxPQUFPLENBQUMsUUFBUSxFQUFFLGVBQWUsRUFBRSxPQUFPLEVBQUUsS0FBSyxFQUFFLElBQW1CLEVBQUUsRUFBRTtRQUNqRixRQUFRLEVBQUUsQ0FBQTtRQUNWLE1BQU0sT0FBTyxHQUFHLFFBQVEsQ0FBQyxJQUFJLENBQWEsQ0FBQTtRQUMxQyxNQUFNLENBQUMsUUFBUSxDQUFDLFFBQVEsR0FBRyxPQUFPLENBQUMsUUFBZSxDQUFBO1FBQ2xELE1BQU0sQ0FBQyxJQUFJLENBQUMsVUFBVSxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsT0FBTyxDQUFDLENBQUE7UUFDM0MsTUFBTSxNQUFNLENBQUMsT0FBTyxDQUFDLENBQUE7SUFDekIsQ0FBQyxDQUFDLENBQUE7QUFDTixDQUFDLENBQUEifQ== \ No newline at end of file +export const command = 'resize'; +export const desc = 'Resizes files'; +export const builder = defaultOptions; +export async function handler(argv) { + defaults(); + const options = sanitize(argv); + logger.settings.minLevel = options.logLevel; + logger.info("options " + argv.dst, options); + await resize(options); +} +cli.command(command, desc, builder, handler); +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVzaXplLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NvbW1hbmRzL3Jlc2l6ZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFDQSxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sYUFBYSxDQUFBO0FBQ3BDLE9BQU8sRUFDSCxNQUFNLEVBQ1QsTUFBTSwrQkFBK0IsQ0FBQTtBQUN0QyxPQUFPLEVBQUUsR0FBRyxFQUFFLE1BQU0sV0FBVyxDQUFBO0FBQy9CLE9BQU8sRUFDSCxRQUFRLEVBQ1IsUUFBUSxFQUNYLE1BQU0sWUFBWSxDQUFBO0FBTW5CLE1BQU0sQ0FBQyxNQUFNLGNBQWMsR0FBRyxDQUFDLEtBQWUsRUFBRSxFQUFFO0lBQzlDLE9BQU8sS0FBSyxDQUFDLE1BQU0sQ0FBQyxLQUFLLEVBQUU7UUFDdkIsUUFBUSxFQUFFLGtCQUFrQjtRQUM1QixZQUFZLEVBQUUsSUFBSTtLQUNyQixDQUFDLENBQUMsTUFBTSxDQUFDLEtBQUssRUFBRTtRQUNiLFFBQVEsRUFBRSxrQkFBa0I7S0FDL0IsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxPQUFPLEVBQUU7UUFDZixPQUFPLEVBQUUsS0FBSztRQUNkLFFBQVEsRUFBRSxnQ0FBZ0M7UUFDMUMsSUFBSSxFQUFFLFNBQVM7S0FDbEIsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxLQUFLLEVBQUU7UUFDYixPQUFPLEVBQUUsS0FBSztRQUNkLFFBQVEsRUFBRSx5Q0FBeUM7UUFDbkQsSUFBSSxFQUFFLFNBQVM7S0FDbEIsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxLQUFLLEVBQUU7UUFDYixPQUFPLEVBQUUsS0FBSztRQUNkLFFBQVEsRUFBRSx3QkFBd0I7UUFDbEMsSUFBSSxFQUFFLFNBQVM7S0FDbEIsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxTQUFTLEVBQUU7UUFDakIsT0FBTyxFQUFFLEtBQUs7UUFDZCxRQUFRLEVBQUUsd0JBQXdCO1FBQ2xDLElBQUksRUFBRSxTQUFTO0tBQ2xCLENBQUMsQ0FBQyxNQUFNLENBQUMsU0FBUyxFQUFFO1FBQ2pCLE9BQU8sRUFBRSxLQUFLO1FBQ2QsUUFBUSxFQUFFLDJCQUEyQjtRQUNyQyxJQUFJLEVBQUUsUUFBUTtLQUNqQixDQUFDLENBQUMsTUFBTSxDQUFDLE9BQU8sRUFBRTtRQUNmLFFBQVEsRUFBRSxtQkFBbUI7UUFDN0IsSUFBSSxFQUFFLFFBQVE7S0FDakIsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxRQUFRLEVBQUU7UUFDaEIsUUFBUSxFQUFFLHFCQUFxQjtRQUMvQixJQUFJLEVBQUUsUUFBUTtLQUNqQixDQUFDLENBQUMsTUFBTSxDQUFDLFdBQVcsRUFBRTtRQUNuQixRQUFRLEVBQUUsNkJBQTZCO1FBQ3ZDLElBQUksRUFBRSxRQUFRO0tBQ2pCLENBQUMsQ0FBQyxNQUFNLENBQUMsVUFBVSxFQUFFO1FBQ2xCLFFBQVEsRUFBRSw0QkFBNEI7UUFDdEMsSUFBSSxFQUFFLFFBQVE7S0FDakIsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxTQUFTLEVBQUU7UUFDakIsUUFBUSxFQUFFLDJCQUEyQjtRQUNyQyxJQUFJLEVBQUUsUUFBUTtLQUNqQixDQUFDLENBQUMsTUFBTSxDQUFDLFNBQVMsRUFBRTtRQUNqQixRQUFRLEVBQUUsaUNBQWlDO1FBQzNDLElBQUksRUFBRSxRQUFRO0tBQ2pCLENBQUMsQ0FBQyxNQUFNLENBQUMsVUFBVSxFQUFFO1FBQ2xCLFFBQVEsRUFBRSxzQ0FBc0M7UUFDaEQsSUFBSSxFQUFFLFFBQVE7UUFDZCxPQUFPLEVBQUUsTUFBTTtLQUNsQixDQUFDLENBQUE7QUFDTixDQUFDLENBQUE7QUFFRCxNQUFNLENBQUMsTUFBTSxPQUFPLEdBQUcsUUFBUSxDQUFDO0FBQ2hDLE1BQU0sQ0FBQyxNQUFNLElBQUksR0FBRyxlQUFlLENBQUM7QUFDcEMsTUFBTSxDQUFDLE1BQU0sT0FBTyxHQUFHLGNBQWMsQ0FBQztBQUV0QyxNQUFNLENBQUMsS0FBSyxVQUFVLE9BQU8sQ0FBQyxJQUFtQjtJQUM3QyxRQUFRLEVBQUUsQ0FBQTtJQUNWLE1BQU0sT0FBTyxHQUFHLFFBQVEsQ0FBQyxJQUFJLENBQWEsQ0FBQTtJQUMxQyxNQUFNLENBQUMsUUFBUSxDQUFDLFFBQVEsR0FBRyxPQUFPLENBQUMsUUFBZSxDQUFBO0lBQ2xELE1BQU0sQ0FBQyxJQUFJLENBQUMsVUFBVSxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsT0FBTyxDQUFDLENBQUE7SUFDM0MsTUFBTSxNQUFNLENBQUMsT0FBTyxDQUFDLENBQUE7QUFDekIsQ0FBQztBQUVELEdBQUcsQ0FBQyxPQUFPLENBQUMsT0FBTyxFQUFFLElBQUksRUFBRSxPQUFPLEVBQUUsT0FBTyxDQUFDLENBQUEifQ== \ No newline at end of file diff --git a/packages/media/dist-in/commands/watermark.d.ts b/packages/media/dist-in/commands/watermark.d.ts index 3298fb71..44463658 100644 --- a/packages/media/dist-in/commands/watermark.d.ts +++ b/packages/media/dist-in/commands/watermark.d.ts @@ -1,3 +1,6 @@ import * as CLI from 'yargs'; export declare const defaultOptions: (yargs: CLI.Argv) => any; -export declare const register: (cli: CLI.Argv) => any; +export declare const command = "watermark"; +export declare const desc = "Adds watermarks to images"; +export declare const builder: (yargs: CLI.Argv) => any; +export declare function handler(argv: CLI.Arguments): Promise; diff --git a/packages/media/dist-in/commands/watermark.js b/packages/media/dist-in/commands/watermark.js index 7c16b144..a3923505 100644 --- a/packages/media/dist-in/commands/watermark.js +++ b/packages/media/dist-in/commands/watermark.js @@ -1,7 +1,7 @@ -import { CONFIG_DEFAULT } from '@polymech/commons'; import { logger } from '../index.js'; -import { watermark } from '../lib/media/images/watermark.js'; +import { cli } from '../cli.js'; import { sanitize, defaults } from '../_cli.js'; +import { watermark } from '../lib/media/images/watermark.js'; export const defaultOptions = (yargs) => { return yargs.option('src', { describe: 'FILE|FOLDER|GLOB', @@ -24,47 +24,98 @@ export const defaultOptions = (yargs) => { default: false, describe: 'Show internal messages', type: 'boolean' - }).option('percent', { - default: false, - describe: 'Resize image with percent', - type: 'number' - }).option('width', { - default: false, - describe: 'Resize image with', - type: 'number' - }).option('height', { - default: false, - describe: 'Resize image height', - type: 'number' - }).option('minHeight', { - describe: 'Resize image minimum height', - type: 'number' - }).option('minWidth', { - describe: 'Resize image minimum width', - type: 'number' - }).option('minSize', { - describe: 'Resize image size (bytes)', - type: 'number' - }).option('percent', { - describe: 'Resize image in percent (width)', - type: 'number' - }).option('key', { - describe: 'API Key', + }).option('logLevel', { + describe: 'Log level : warn, info, debug, error', + type: 'string', + default: 'info' + }).option('watermarkType', { + describe: 'Type of watermark: text or image', + choices: ['text', 'image'], + demandOption: true + }).option('text', { + describe: 'Text to use for text watermark', type: 'string' + }).option('logoPath', { + describe: 'Path to logo image for image watermark', + type: 'string' + }).option('position', { + describe: 'Position of watermark', + choices: ['top-left', 'top-right', 'bottom-left', 'bottom-right', 'center'], + default: 'bottom-right' + }).option('margin', { + describe: 'Margin from edges in pixels', + type: 'number', + default: 24 + }).option('opacity', { + describe: 'Opacity of watermark (0-1)', + type: 'number', + default: 0.85 + }).option('sizePct', { + describe: 'Size of image watermark as percentage of base image width (0-1)', + type: 'number', + default: 0.2 + }).option('fontSize', { + describe: 'Font size for text watermark in pixels', + type: 'number', + default: 48 + }).option('color', { + describe: 'Text color (hex format, e.g., #ffffff)', + type: 'string', + default: '#ffffff' + }).option('fontFamily', { + describe: 'Font family for text watermark', + type: 'string', + default: 'Arial' + }).option('strokeColor', { + describe: 'Text stroke color (hex format, e.g., #000000)', + type: 'string', + default: '#000000' + }).option('strokeWidth', { + describe: 'Text stroke width in pixels', + type: 'number', + default: 2 }); }; -const options = (yargs) => defaultOptions(yargs); -export const register = (cli) => { - return cli.command('watermark', 'Remove watermark : FILE|GLOB', options, async (argv) => { - defaults(); - const options = sanitize(argv); - const config = CONFIG_DEFAULT(); - if (!config.novita) { - logger.error("Novita key not found"); - return; - } - options.debug && logger.info("Watermark Options " + argv.dst, options); - return watermark({ ...options, key: config.novita.key }); - }); -}; -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid2F0ZXJtYXJrLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NvbW1hbmRzL3dhdGVybWFyay50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sbUJBQW1CLENBQUE7QUFFbEQsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLGFBQWEsQ0FBQTtBQUNwQyxPQUFPLEVBQ0wsU0FBUyxFQUNWLE1BQU0sa0NBQWtDLENBQUE7QUFFekMsT0FBTyxFQUNMLFFBQVEsRUFDUixRQUFRLEVBQ1QsTUFBTSxZQUFZLENBQUE7QUFNbkIsTUFBTSxDQUFDLE1BQU0sY0FBYyxHQUFHLENBQUMsS0FBZSxFQUFFLEVBQUU7SUFDaEQsT0FBTyxLQUFLLENBQUMsTUFBTSxDQUFDLEtBQUssRUFBRTtRQUN6QixRQUFRLEVBQUUsa0JBQWtCO1FBQzVCLFlBQVksRUFBRSxJQUFJO0tBQ25CLENBQUMsQ0FBQyxNQUFNLENBQUMsS0FBSyxFQUFFO1FBQ2YsUUFBUSxFQUFFLGtCQUFrQjtLQUM3QixDQUFDLENBQUMsTUFBTSxDQUFDLE9BQU8sRUFBRTtRQUNqQixPQUFPLEVBQUUsS0FBSztRQUNkLFFBQVEsRUFBRSxnQ0FBZ0M7UUFDMUMsSUFBSSxFQUFFLFNBQVM7S0FDaEIsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxLQUFLLEVBQUU7UUFDZixPQUFPLEVBQUUsS0FBSztRQUNkLFFBQVEsRUFBRSx5Q0FBeUM7UUFDbkQsSUFBSSxFQUFFLFNBQVM7S0FDaEIsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxLQUFLLEVBQUU7UUFDZixPQUFPLEVBQUUsS0FBSztRQUNkLFFBQVEsRUFBRSx3QkFBd0I7UUFDbEMsSUFBSSxFQUFFLFNBQVM7S0FDaEIsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxTQUFTLEVBQUU7UUFDbkIsT0FBTyxFQUFFLEtBQUs7UUFDZCxRQUFRLEVBQUUsd0JBQXdCO1FBQ2xDLElBQUksRUFBRSxTQUFTO0tBQ2hCLENBQUMsQ0FBQyxNQUFNLENBQUMsU0FBUyxFQUFFO1FBQ25CLE9BQU8sRUFBRSxLQUFLO1FBQ2QsUUFBUSxFQUFFLDJCQUEyQjtRQUNyQyxJQUFJLEVBQUUsUUFBUTtLQUNmLENBQUMsQ0FBQyxNQUFNLENBQUMsT0FBTyxFQUFFO1FBQ2pCLE9BQU8sRUFBRSxLQUFLO1FBQ2QsUUFBUSxFQUFFLG1CQUFtQjtRQUM3QixJQUFJLEVBQUUsUUFBUTtLQUNmLENBQUMsQ0FBQyxNQUFNLENBQUMsUUFBUSxFQUFFO1FBQ2xCLE9BQU8sRUFBRSxLQUFLO1FBQ2QsUUFBUSxFQUFFLHFCQUFxQjtRQUMvQixJQUFJLEVBQUUsUUFBUTtLQUNmLENBQUMsQ0FBQyxNQUFNLENBQUMsV0FBVyxFQUFFO1FBQ3JCLFFBQVEsRUFBRSw2QkFBNkI7UUFDdkMsSUFBSSxFQUFFLFFBQVE7S0FDZixDQUFDLENBQUMsTUFBTSxDQUFDLFVBQVUsRUFBRTtRQUNwQixRQUFRLEVBQUUsNEJBQTRCO1FBQ3RDLElBQUksRUFBRSxRQUFRO0tBQ2YsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxTQUFTLEVBQUU7UUFDbkIsUUFBUSxFQUFFLDJCQUEyQjtRQUNyQyxJQUFJLEVBQUUsUUFBUTtLQUNmLENBQUMsQ0FBQyxNQUFNLENBQUMsU0FBUyxFQUFFO1FBQ25CLFFBQVEsRUFBRSxpQ0FBaUM7UUFDM0MsSUFBSSxFQUFFLFFBQVE7S0FDZixDQUFDLENBQUMsTUFBTSxDQUFDLEtBQUssRUFBRTtRQUNmLFFBQVEsRUFBRSxTQUFTO1FBQ25CLElBQUksRUFBRSxRQUFRO0tBQ2YsQ0FBQyxDQUFBO0FBQ0osQ0FBQyxDQUFBO0FBRUQsTUFBTSxPQUFPLEdBQUcsQ0FBQyxLQUFlLEVBQUUsRUFBRSxDQUFDLGNBQWMsQ0FBQyxLQUFLLENBQUMsQ0FBQTtBQUUxRCxNQUFNLENBQUMsTUFBTSxRQUFRLEdBQUcsQ0FBQyxHQUFhLEVBQUUsRUFBRTtJQUN4QyxPQUFPLEdBQUcsQ0FBQyxPQUFPLENBQUMsV0FBVyxFQUFFLDhCQUE4QixFQUFFLE9BQU8sRUFBRSxLQUFLLEVBQUUsSUFBbUIsRUFBRSxFQUFFO1FBQ3JHLFFBQVEsRUFBRSxDQUFBO1FBQ1YsTUFBTSxPQUFPLEdBQUcsUUFBUSxDQUFDLElBQUksQ0FBYSxDQUFBO1FBQzFDLE1BQU0sTUFBTSxHQUFRLGNBQWMsRUFBRSxDQUFBO1FBQ3BDLElBQUksQ0FBQyxNQUFNLENBQUMsTUFBTSxFQUFFLENBQUM7WUFDbkIsTUFBTSxDQUFDLEtBQUssQ0FBQyxzQkFBc0IsQ0FBQyxDQUFDO1lBQ3JDLE9BQU07UUFDUixDQUFDO1FBQ0QsT0FBTyxDQUFDLEtBQUssSUFBSSxNQUFNLENBQUMsSUFBSSxDQUFDLG9CQUFvQixHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsT0FBTyxDQUFDLENBQUE7UUFDdEUsT0FBTyxTQUFTLENBQUMsRUFBRSxHQUFHLE9BQU8sRUFBRSxHQUFHLEVBQUUsTUFBTSxDQUFDLE1BQU0sQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFBO0lBQzFELENBQUMsQ0FBQyxDQUFBO0FBQ0osQ0FBQyxDQUFBIn0= \ No newline at end of file +export const command = 'watermark'; +export const desc = 'Adds watermarks to images'; +export const builder = defaultOptions; +export async function handler(argv) { + defaults(); + const options = sanitize(argv); + logger.settings.minLevel = options.logLevel; + // Validate required options based on watermark type + if (options.watermarkType === 'text' && !options.text) { + logger.error('Text is required when using text watermark type'); + process.exit(1); + } + if (options.watermarkType === 'image' && !options.logoPath) { + logger.error('Logo path is required when using image watermark type'); + process.exit(1); + } + // Set up watermark options based on type + if (options.watermarkType === 'text') { + options.textOptions = { + position: argv.position, + margin: argv.margin, + fontSize: argv.fontSize, + opacity: argv.opacity, + color: argv.color, + fontFamily: argv.fontFamily, + strokeColor: argv.strokeColor, + strokeWidth: argv.strokeWidth, + }; + } + else if (options.watermarkType === 'image') { + options.imageOptions = { + position: argv.position, + margin: argv.margin, + sizePct: argv.sizePct, + opacity: argv.opacity, + blend: 'over' + }; + } + logger.info("Adding watermark with options:", options); + await watermark(options); +} +cli.command(command, desc, builder, handler); +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid2F0ZXJtYXJrLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NvbW1hbmRzL3dhdGVybWFyay50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFDQSxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sYUFBYSxDQUFBO0FBQ3BDLE9BQU8sRUFBRSxHQUFHLEVBQUUsTUFBTSxXQUFXLENBQUE7QUFDL0IsT0FBTyxFQUNILFFBQVEsRUFDUixRQUFRLEVBQ1gsTUFBTSxZQUFZLENBQUE7QUFNbkIsT0FBTyxFQUNILFNBQVMsRUFFWixNQUFNLGtDQUFrQyxDQUFBO0FBRXpDLE1BQU0sQ0FBQyxNQUFNLGNBQWMsR0FBRyxDQUFDLEtBQWUsRUFBRSxFQUFFO0lBQzlDLE9BQU8sS0FBSyxDQUFDLE1BQU0sQ0FBQyxLQUFLLEVBQUU7UUFDdkIsUUFBUSxFQUFFLGtCQUFrQjtRQUM1QixZQUFZLEVBQUUsSUFBSTtLQUNyQixDQUFDLENBQUMsTUFBTSxDQUFDLEtBQUssRUFBRTtRQUNiLFFBQVEsRUFBRSxrQkFBa0I7S0FDL0IsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxPQUFPLEVBQUU7UUFDZixPQUFPLEVBQUUsS0FBSztRQUNkLFFBQVEsRUFBRSxnQ0FBZ0M7UUFDMUMsSUFBSSxFQUFFLFNBQVM7S0FDbEIsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxLQUFLLEVBQUU7UUFDYixPQUFPLEVBQUUsS0FBSztRQUNkLFFBQVEsRUFBRSx5Q0FBeUM7UUFDbkQsSUFBSSxFQUFFLFNBQVM7S0FDbEIsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxLQUFLLEVBQUU7UUFDYixPQUFPLEVBQUUsS0FBSztRQUNkLFFBQVEsRUFBRSx3QkFBd0I7UUFDbEMsSUFBSSxFQUFFLFNBQVM7S0FDbEIsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxTQUFTLEVBQUU7UUFDakIsT0FBTyxFQUFFLEtBQUs7UUFDZCxRQUFRLEVBQUUsd0JBQXdCO1FBQ2xDLElBQUksRUFBRSxTQUFTO0tBQ2xCLENBQUMsQ0FB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 \ No newline at end of file diff --git a/packages/media/dist-in/lib/media/images/background-remove.d.ts b/packages/media/dist-in/lib/media/images/background-remove.d.ts new file mode 100644 index 00000000..afc5ef9c --- /dev/null +++ b/packages/media/dist-in/lib/media/images/background-remove.d.ts @@ -0,0 +1,11 @@ +import { IOptions } from '../../../types.js'; +export interface BackgroundRemoveOptions extends IOptions { + apiKey?: string; + model?: string; + alpha_matting?: boolean; + alpha_matting_foreground_threshold?: number; + alpha_matting_background_threshold?: number; + alpha_matting_erode_size?: number; +} +export declare function removeBackgroundFile(inputPath: string, outputPath: string, options: BackgroundRemoveOptions): Promise; +export declare const backgroundRemove: (options: BackgroundRemoveOptions) => Promise; diff --git a/packages/media/dist-in/lib/media/images/background-remove.js b/packages/media/dist-in/lib/media/images/background-remove.js new file mode 100644 index 00000000..d7f87167 --- /dev/null +++ b/packages/media/dist-in/lib/media/images/background-remove.js @@ -0,0 +1,117 @@ +import * as fs from 'fs'; +import * as path from 'path'; +import pMap from 'p-map'; +import { logger } from '../../../index.js'; +import { targets } from '../../index.js'; +import { sync as mkdir } from '@polymech/fs/dir'; +// Base64 encode image file +function encodeImageToBase64(filePath) { + const imageBuffer = fs.readFileSync(filePath); + return `data:image/${path.extname(filePath).slice(1)};base64,${imageBuffer.toString('base64')}`; +} +// Save FileOutput from Replicate API to file +async function saveReplicateOutput(output, outputPath) { + // Ensure output directory exists + mkdir(path.dirname(outputPath)); + // Handle FileOutput from Replicate API + if (output && typeof output.url === 'function') { + // This is a FileOutput object from Replicate + logger.debug(`Saving FileOutput to: ${outputPath}`); + await fs.promises.writeFile(outputPath, output); + } + else if (typeof output === 'string' && output.startsWith('http')) { + // This is a URL, fetch and save the image + logger.debug(`Downloading image from URL: ${output}`); + const response = await fetch(output); + const arrayBuffer = await response.arrayBuffer(); + const buffer = Buffer.from(arrayBuffer); + fs.writeFileSync(outputPath, buffer); + } + else if (typeof output === 'string') { + // This might be base64 data + let base64String = output.replace(/^data:image\/[a-z]+;base64,/, ''); + const imageBuffer = Buffer.from(base64String, 'base64'); + fs.writeFileSync(outputPath, imageBuffer); + } + else if (Buffer.isBuffer(output)) { + // Already a buffer + fs.writeFileSync(outputPath, output); + } + else { + throw new Error(`Unexpected output format: ${typeof output}, ${JSON.stringify(output).substring(0, 200)}`); + } +} +export async function removeBackgroundFile(inputPath, outputPath, options) { + try { + if (!options.apiKey) { + throw new Error('Replicate API key is required. Set it via --apiKey or REPLICATE_API_TOKEN environment variable'); + } + // Import Replicate dynamically to handle potential installation issues + let Replicate; + try { + const replicateModule = await import('replicate'); + Replicate = replicateModule.default; + } + catch (error) { + throw new Error('Replicate package not found. Please install it with: npm install replicate'); + } + const replicate = new Replicate({ + auth: options.apiKey, + }); + logger.debug(`Removing background from ${inputPath}`); + // Encode input image to base64 data URL + const inputImageBase64 = encodeImageToBase64(inputPath); + // Prepare input for the model + const input = { + image: inputImageBase64, + model: options.model || 'u2net', + alpha_matting: options.alpha_matting || false, + alpha_matting_foreground_threshold: options.alpha_matting_foreground_threshold || 270, + alpha_matting_background_threshold: options.alpha_matting_background_threshold || 10, + alpha_matting_erode_size: options.alpha_matting_erode_size || 10, + }; + // Run the background removal model + const output = await replicate.run("cjwbw/rembg:fb8af171cfa1616ddcf1242c093f9c46bcada5ad4cf6f2fbe8b81b330ec5c003", { + input + }); + logger.debug(`API response type: ${typeof output}`); + logger.debug(`API response has url method: ${typeof output?.url}`); + if (output && typeof output.url === 'function') { + logger.debug(`Output URL: ${output.url()}`); + } + // Save the result + await saveReplicateOutput(output, outputPath); + logger.info(`Background removed: ${inputPath} → ${outputPath}`); + } + catch (error) { + logger.error(`Failed to remove background from ${inputPath}:`, error.message); + throw error; + } +} +const _backgroundRemove = async (file, targets, onNode = () => { }, options) => { + return pMap(targets, async (target) => { + options.verbose && logger.debug(`Removing background ${file} to ${target}`); + if (options.dry) { + logger.info(`[DRY RUN] Would remove background: ${file} → ${target}`); + return; + } + return await removeBackgroundFile(file, target, options); + }, { concurrency: 1 }); +}; +export const backgroundRemove = async (options) => { + // reporting, stub + let reports = []; + const onNode = (data) => reports.push(data); + if (options.srcInfo) { + options.verbose && logger.info(`Removing background from ${options.srcInfo.FILES.length} files`); + return await pMap(options.srcInfo.FILES, async (f) => { + const outputs = targets(f, options); + options.verbose && logger.info(`Removing background ${f} to`, outputs); + return _backgroundRemove(f, outputs, onNode, options); + }, { concurrency: 1 }); + } + else { + options.debug && logger.error(`Invalid source info`); + } +}; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmFja2dyb3VuZC1yZW1vdmUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvbGliL21lZGlhL2ltYWdlcy9iYWNrZ3JvdW5kLXJlbW92ZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssRUFBRSxNQUFNLElBQUksQ0FBQztBQUN6QixPQUFPLEtBQUssSUFBSSxNQUFNLE1BQU0sQ0FBQztBQUM3QixPQUFPLElBQUksTUFBTSxPQUFPLENBQUM7QUFDekIsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBRTNDLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUN6QyxPQUFPLEVBQUUsSUFBSSxJQUFJLEtBQUssRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBWWpELDJCQUEyQjtBQUMzQixTQUFTLG1CQUFtQixDQUFDLFFBQWdCO0lBQzNDLE1BQU0sV0FBVyxHQUFHLEVBQUUsQ0FBQyxZQUFZLENBQUMsUUFBUSxDQUFDLENBQUM7SUFDOUMsT0FBTyxjQUFjLElBQUksQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxXQUFXLFdBQVcsQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQztBQUNsRyxDQUFDO0FBRUQsNkNBQTZDO0FBQzdDLEtBQUssVUFBVSxtQkFBbUIsQ0FBQyxNQUFXLEVBQUUsVUFBa0I7SUFDaEUsaUNBQWlDO0lBQ2pDLEtBQUssQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUM7SUFFaEMsdUNBQXVDO0lBQ3ZDLElBQUksTUFBTSxJQUFJLE9BQU8sTUFBTSxDQUFDLEdBQUcsS0FBSyxVQUFVLEVBQUUsQ0FBQztRQUMvQyw2Q0FBNkM7UUFDN0MsTUFBTSxDQUFDLEtBQUssQ0FBQyx5QkFBeUIsVUFBVSxFQUFFLENBQUMsQ0FBQztRQUNwRCxNQUFNLEVBQUUsQ0FB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 \ No newline at end of file diff --git a/packages/media/dist-in/lib/media/images/watermark.d.ts b/packages/media/dist-in/lib/media/images/watermark.d.ts index aff0506a..d4b37aed 100644 --- a/packages/media/dist-in/lib/media/images/watermark.d.ts +++ b/packages/media/dist-in/lib/media/images/watermark.d.ts @@ -1,2 +1,31 @@ +import { OverlayOptions } from "sharp"; import { IOptions } from '../../../types.js'; -export declare const watermark: (options: IOptions) => Promise; +type Corner = "top-left" | "top-right" | "bottom-left" | "bottom-right" | "center"; +export interface LogoWatermarkOptions { + position?: Corner; + margin?: number; + sizePct?: number; + opacity?: number; + blend?: OverlayOptions["blend"]; +} +export interface TextWatermarkOptions { + position?: Corner; + margin?: number; + fontSize?: number; + opacity?: number; + color?: string; + fontFamily?: string; + strokeColor?: string; + strokeWidth?: number; +} +export interface WatermarkOptions extends IOptions { + watermarkType: 'text' | 'image'; + text?: string; + textOptions?: TextWatermarkOptions; + logoPath?: string; + imageOptions?: LogoWatermarkOptions; +} +export declare function addLogoWatermark(inputPath: string, logoPath: string, outputPath: string, opts?: LogoWatermarkOptions): Promise; +export declare function addTextWatermark(inputPath: string, text: string, outputPath: string, opts?: TextWatermarkOptions): Promise; +export declare const watermark: (options: WatermarkOptions) => Promise; +export {}; diff --git a/packages/media/dist-in/lib/media/images/watermark.js b/packages/media/dist-in/lib/media/images/watermark.js index 8e5b6895..cfed4606 100644 --- a/packages/media/dist-in/lib/media/images/watermark.js +++ b/packages/media/dist-in/lib/media/images/watermark.js @@ -1,31 +1,156 @@ -import BPromise from 'bluebird'; -import { async as write } from "@polymech/fs/write"; +import sharp from "sharp"; +import * as path from 'path'; +import * as fs from 'fs'; +import pMap from 'p-map'; import { logger } from '../../../index.js'; -import { imageToBase64, base64ToBuffer } from './lib.js'; -import { NovitaSDK } from "novita-sdk"; import { targets } from '../../index.js'; -const removeWatermark = async (file, target, onNode = () => { }, options) => { - const novitaClient = new NovitaSDK(options.key); - const params = { - image_file: await imageToBase64(file) - //"data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD", - }; - try { - const wMark = await novitaClient.removeWatermark(params); - logger.info(`Watermark removed: ${file} to ${target}`); - write(target, base64ToBuffer(wMark.image_file)); - } - catch (error) { - logger.error(`Failed to remove watermark: ${error.msg}`); - } -}; -const _watermark = async (file, targets, onNode = () => { }, options) => { - return BPromise.resolve(targets).map((target) => { - options.verbose && logger.debug(`Removing Watermark ${file} to ${target}`); - if (options.dry) { - return BPromise.resolve(); +import { sync as mkdir } from '@polymech/fs/dir'; +export async function addLogoWatermark(inputPath, logoPath, outputPath, opts = {}) { + const { position = "bottom-right", margin = 24, sizePct = 0.2, opacity = 0.85, blend = "over", } = opts; + const base = sharp(inputPath); + const { width: W = 0, height: H = 0 } = await base.metadata(); + if (!W || !H) + throw new Error("Could not read base image size"); + // Resize logo to sizePct of base width + const logoWidth = Math.max(1, Math.round(W * sizePct)); + const logoBuf = await sharp(logoPath).resize({ width: logoWidth }).toBuffer(); + const { width: w = 0, height: h = 0 } = await sharp(logoBuf).metadata(); + // Compute pixel placement + const pos = (() => { + switch (position) { + case "top-left": return { left: margin, top: margin }; + case "top-right": return { left: W - w - margin, top: margin }; + case "bottom-left": return { left: margin, top: H - h - margin }; + case "center": return { left: Math.round((W - w) / 2), top: Math.round((H - h) / 2) }; + case "bottom-right": + default: return { left: W - w - margin, top: H - h - margin }; + } + })(); + // Ensure output directory exists + mkdir(path.dirname(outputPath)); + await base + .composite([{ + input: logoBuf, + left: pos.left, + top: pos.top, + blend, + ...(opacity < 1 ? { blend: 'multiply' } : {}), + }]) + .toFile(outputPath); +} +export async function addTextWatermark(inputPath, text, outputPath, opts = {}) { + const { position = "bottom-right", margin = 24, fontSize = 48, opacity = 0.8, color = '#ffffff', fontFamily = 'Arial', strokeColor = '#000000', strokeWidth = 2, } = opts; + const base = sharp(inputPath); + const { width: W = 0, height: H = 0 } = await base.metadata(); + if (!W || !H) + throw new Error("Could not read base image size"); + // Create SVG text element + const svgText = ` + + + ${text} + + + `; + const textBuffer = Buffer.from(svgText); + // Ensure output directory exists + mkdir(path.dirname(outputPath)); + await base + .composite([{ + input: textBuffer, + left: 0, + top: 0, + blend: 'over', + }]) + .toFile(outputPath); +} +function getTextX(position, width, margin) { + switch (position) { + case "top-left": + case "bottom-left": + return margin; + case "top-right": + case "bottom-right": + return width - margin; + case "center": + default: + return width / 2; + } +} +function getTextY(position, height, margin, fontSize) { + switch (position) { + case "top-left": + case "top-right": + return margin + fontSize; + case "bottom-left": + case "bottom-right": + return height - margin; + case "center": + default: + return height / 2; + } +} +function getTextAnchor(position) { + switch (position) { + case "top-left": + case "bottom-left": + return "start"; + case "top-right": + case "bottom-right": + return "end"; + case "center": + default: + return "middle"; + } +} +function getTextBaseline(position) { + switch (position) { + case "top-left": + case "top-right": + return "hanging"; + case "bottom-left": + case "bottom-right": + return "auto"; + case "center": + default: + return "middle"; + } +} +const _watermark = async (file, targets, onNode = () => { }, options) => { + return pMap(targets, async (target) => { + options.verbose && logger.debug(`Adding watermark ${file} to ${target}`); + if (options.dry) { + return; + } + if (options.watermarkType === 'text') { + if (!options.text) { + throw new Error('Text is required for text watermark'); + } + return addTextWatermark(file, options.text, target, options.textOptions); + } + else if (options.watermarkType === 'image') { + if (!options.logoPath) { + throw new Error('Logo path is required for image watermark'); + } + if (!fs.existsSync(options.logoPath)) { + throw new Error(`Logo file not found: ${options.logoPath}`); + } + return addLogoWatermark(file, options.logoPath, target, options.imageOptions); + } + else { + throw new Error('Invalid watermark type. Must be "text" or "image"'); } - return removeWatermark(file, target, onNode, options); }, { concurrency: 1 }); }; export const watermark = async (options) => { @@ -33,10 +158,10 @@ export const watermark = async (options) => { let reports = []; const onNode = (data) => reports.push(data); if (options.srcInfo) { - options.verbose && logger.info(`Convert ${options.srcInfo.FILES.length} files`); - return await BPromise.resolve(options.srcInfo.FILES).map((f) => { + options.verbose && logger.info(`Adding watermark to ${options.srcInfo.FILES.length} files`); + return await pMap(options.srcInfo.FILES, async (f) => { const outputs = targets(f, options); - options.verbose && logger.info(`Convert ${f} to `, outputs); + options.verbose && logger.info(`Adding watermark ${f} to `, outputs); return _watermark(f, outputs, onNode, options); }, { concurrency: 1 }); } @@ -44,4 +169,4 @@ export const watermark = async (options) => { options.debug && logger.error(`Invalid source info`); } }; -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid2F0ZXJtYXJrLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2xpYi9tZWRpYS9pbWFnZXMvd2F0ZXJtYXJrLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUlBLE9BQU8sUUFBUSxNQUFNLFVBQVUsQ0FBQTtBQUMvQixPQUFPLEVBQUUsS0FBSyxJQUFJLEtBQUssRUFBRSxNQUFNLG9CQUFvQixDQUFBO0FBQ25ELE9BQU8sRUFDSCxNQUFNLEVBQ1QsTUFBTSxtQkFBbUIsQ0FBQTtBQU8xQixPQUFPLEVBQ0gsYUFBYSxFQUNiLGNBQWMsRUFDakIsTUFBTSxVQUFVLENBQUE7QUFHakIsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLFlBQVksQ0FBQTtBQUN0QyxPQUFPLEVBQUcsT0FBTyxFQUFlLE1BQU0sZ0JBQWdCLENBQUE7QUFFdEQsTUFBTSxlQUFlLEdBQUcsS0FBSyxFQUFFLElBQUksRUFBRSxNQUFNLEVBQUUsU0FBOEIsR0FBRyxFQUFFLEdBQUcsQ0FBQyxFQUFFLE9BQXVCLEVBQUUsRUFBRTtJQUM3RyxNQUFNLFlBQVksR0FBRyxJQUFJLFNBQVMsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLENBQUE7SUFDL0MsTUFBTSxNQUFNLEdBQUc7UUFDWCxVQUFVLEVBQUUsTUFBTSxhQUFhLENBQUMsSUFBSSxDQUFDO1FBQ3JDLHVEQUF1RDtLQUMxRCxDQUFBO0lBQ0QsSUFBSSxDQUFDO1FBQ0QsTUFBTSxLQUFLLEdBQUcsTUFBTSxZQUFZLENBQUMsZUFBZSxDQUFDLE1BQU0sQ0FBQyxDQUFBO1FBQ3hELE1BQU0sQ0FBQyxJQUFJLENBQUMsc0JBQXNCLElBQUksT0FBTyxNQUFNLEVBQUUsQ0FBQyxDQUFBO1FBQ3RELEtBQUssQ0FBQyxNQUFNLEVBQUMsY0FBYyxDQUFDLEtBQUssQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFBO0lBQ2xELENBQUM7SUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO1FBQ2IsTUFBTSxDQUFDLEtBQUssQ0FBQywrQkFBK0IsS0FBSyxDQUFDLEdBQUcsRUFBRSxDQUFDLENBQUE7SUFDNUQsQ0FBQztBQUNMLENBQUMsQ0FBQTtBQUVELE1BQU0sVUFBVSxHQUFHLEtBQUssRUFBRSxJQUFJLEVBQUUsT0FBaUIsRUFBRSxTQUE4QixHQUFHLEVBQUUsR0FBRyxDQUFDLEVBQUUsT0FBaUIsRUFBRSxFQUFFO0lBQzdHLE9BQU8sUUFBUSxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxNQUFNLEVBQUUsRUFBRTtRQUM1QyxPQUFPLENBQUMsT0FBTyxJQUFJLE1BQU0sQ0FBQyxLQUFLLENBQUMsc0JBQXNCLElBQUksT0FBTyxNQUFNLEVBQUUsQ0FBQyxDQUFBO1FBQzFFLElBQUksT0FBTyxDQUFDLEdBQUcsRUFBRSxDQUFDO1lBQ2QsT0FBTyxRQUFRLENBQUMsT0FBTyxFQUFFLENBQUE7UUFDN0IsQ0FBQztRQUNELE9BQU8sZUFBZSxDQUFDLElBQUksRUFBRSxNQUFNLEVBQUUsTUFBTSxFQUFFLE9BQU8sQ0FBQyxDQUFDO0lBQzFELENBQUMsRUFBRSxFQUFFLFdBQVcsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFBO0FBQzFCLENBQUMsQ0FBQTtBQUVELE1BQU0sQ0FBQyxNQUFNLFNBQVMsR0FBRyxLQUFLLEVBQUUsT0FBaUIsRUFBRSxFQUFFO0lBRWpELGtCQUFrQjtJQUNsQixJQUFJLE9BQU8sR0FBUSxFQUFFLENBQUE7SUFDckIsTUFBTSxNQUFNLEdBQUcsQ0FBQyxJQUFTLEVBQUUsRUFBRSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUE7SUFDaEQsSUFBSSxPQUFPLENBQUMsT0FBTyxFQUFFLENBQUM7UUFDbEIsT0FBTyxDQUFDLE9BQU8sSUFBSSxNQUFNLENBQUMsSUFBSSxDQUFDLFdBQVcsT0FBTyxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsTUFBTSxRQUFRLENBQUMsQ0FBQTtRQUMvRSxPQUFPLE1BQU0sUUFBUSxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFO1lBQzNELE1BQU0sT0FBTyxHQUFHLE9BQU8sQ0FBQyxDQUFDLEVBQUUsT0FBTyxDQUFDLENBQUE7WUFDbkMsT0FBTyxDQUFDLE9BQU8sSUFBSSxNQUFNLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxNQUFNLEVBQUUsT0FBTyxDQUFDLENBQUE7WUFDM0QsT0FBTyxVQUFVLENBQUMsQ0FBQyxFQUFFLE9BQU8sRUFBRSxNQUFNLEVBQUUsT0FBTyxDQUFDLENBQUE7UUFDbEQsQ0FBQyxFQUFFLEVBQUUsV0FBVyxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUE7SUFDMUIsQ0FBQztTQUFNLENBQUM7UUFDSixPQUFPLENBQUMsS0FBSyxJQUFJLE1BQU0sQ0FBQyxLQUFLLENBQUMscUJBQXFCLENBQUMsQ0FBQTtJQUN4RCxDQUFDO0FBQ0wsQ0FBQyxDQUFBIn0= \ No newline at end of file +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid2F0ZXJtYXJrLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2xpYi9tZWRpYS9pbWFnZXMvd2F0ZXJtYXJrLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBeUIsTUFBTSxPQUFPLENBQUM7QUFDOUMsT0FBTyxLQUFLLElBQUksTUFBTSxNQUFNLENBQUM7QUFDN0IsT0FBTyxLQUFLLEVBQUUsTUFBTSxJQUFJLENBQUM7QUFFekIsT0FBTyxJQUFJLE1BQU0sT0FBTyxDQUFDO0FBQ3pCLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQztBQUUzQyxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDekMsT0FBTyxFQUFFLElBQUksSUFBSSxLQUFLLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQTtBQW9DaEQsTUFBTSxDQUFDLEtBQUssVUFBVSxnQkFBZ0IsQ0FDcEMsU0FBaUIsRUFDakIsUUFBZ0IsRUFDaEIsVUFBa0IsRUFDbEIsT0FBNkIsRUFBRTtJQUUvQixNQUFNLEVBQ0osUUFBUSxHQUFHLGNBQWMsRUFDekIsTUFBTSxHQUFHLEVBQUUsRUFDWCxPQUFPLEdBQUcsR0FBRyxFQUNiLE9BQU8sR0FBRyxJQUFJLEVBQ2QsS0FBSyxHQUFHLE1BQU0sR0FDZixHQUFHLElBQUksQ0FBQztJQUVULE1BQU0sSUFBSSxHQUFHLEtBQUssQ0FBQyxTQUFTLENBQUMsQ0FBQztJQUM5QixNQUFNLEVBQUUsS0FBSyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsTUFBTSxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsR0FBRyxNQUFNLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQztJQUM5RCxJQUFJLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUFFLE1BQU0sSUFBSSxLQUFLLENBQUMsZ0NBQWdDLENBQUMsQ0FBQztJQUVoRSx1Q0FBdUM7SUFDdkMsTUFBTSxTQUFTLEdBQUcsSUFBSSxD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 \ No newline at end of file diff --git a/packages/media/dist-in/main.d.ts b/packages/media/dist-in/main.d.ts index 6e01b188..d309645f 100644 --- a/packages/media/dist-in/main.d.ts +++ b/packages/media/dist-in/main.d.ts @@ -1,3 +1,5 @@ #!/usr/bin/env node import './commands/resize.js'; import './commands/pdf2jpg.js'; +import './commands/watermark.js'; +import './commands/background-remove.js'; diff --git a/packages/media/dist-in/main.js b/packages/media/dist-in/main.js index 1a41c861..9a322044 100644 --- a/packages/media/dist-in/main.js +++ b/packages/media/dist-in/main.js @@ -4,6 +4,8 @@ defaults(); import { cli } from './cli.js'; import './commands/resize.js'; import './commands/pdf2jpg.js'; +import './commands/watermark.js'; +import './commands/background-remove.js'; const argv = cli.argv; if (argv.h || argv.help) { cli.showHelp(); @@ -12,4 +14,4 @@ if (argv.h || argv.help) { else if (argv.v || argv.version) { process.exit(); } -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWFpbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9tYWluLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFDQSxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sV0FBVyxDQUFDO0FBQUMsUUFBUSxFQUFFLENBQUE7QUFFaEQsT0FBTyxFQUFFLEdBQUcsRUFBRSxNQUFNLFVBQVUsQ0FBQTtBQUM5QixPQUFPLHNCQUFzQixDQUFBO0FBQzdCLE9BQU8sdUJBQXVCLENBQUE7QUFFOUIsTUFBTSxJQUFJLEdBQVEsR0FBRyxDQUFDLElBQUksQ0FBQztBQUUzQixJQUFJLElBQUksQ0FBQyxDQUFDLElBQUksSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO0lBQ3RCLEdBQUcsQ0FBQyxRQUFRLEVBQUUsQ0FBQztJQUNmLE9BQU8sQ0FBQyxJQUFJLEVBQUUsQ0FBQztBQUNuQixDQUFDO0tBQU0sSUFBSSxJQUFJLENBQUMsQ0FBQyxJQUFJLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQztJQUNoQyxPQUFPLENBQUMsSUFBSSxFQUFFLENBQUM7QUFDbkIsQ0FBQyJ9 \ No newline at end of file +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWFpbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9tYWluLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFDQSxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sV0FBVyxDQUFDO0FBQUMsUUFBUSxFQUFFLENBQUE7QUFFaEQsT0FBTyxFQUFFLEdBQUcsRUFBRSxNQUFNLFVBQVUsQ0FBQTtBQUU5QixPQUFPLHNCQUFzQixDQUFBO0FBQzdCLE9BQU8sdUJBQXVCLENBQUE7QUFDOUIsT0FBTyx5QkFBeUIsQ0FBQTtBQUNoQyxPQUFPLGlDQUFpQyxDQUFBO0FBRXhDLE1BQU0sSUFBSSxHQUFRLEdBQUcsQ0FBQyxJQUFJLENBQUM7QUFFM0IsSUFBSSxJQUFJLENBQUMsQ0FBQyxJQUFJLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQztJQUN0QixHQUFHLENBQUMsUUFBUSxFQUFFLENBQUM7SUFDZixPQUFPLENBQUMsSUFBSSxFQUFFLENBQUM7QUFDbkIsQ0FBQztLQUFNLElBQUksSUFBSSxDQUFDLENBQUMsSUFBSSxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUM7SUFDaEMsT0FBTyxDQUFDLElBQUksRUFBRSxDQUFDO0FBQ25CLENBQUMifQ== \ No newline at end of file diff --git a/packages/media/dist-in/types.d.ts b/packages/media/dist-in/types.d.ts index 3534f691..60c95487 100644 --- a/packages/media/dist-in/types.d.ts +++ b/packages/media/dist-in/types.d.ts @@ -50,3 +50,5 @@ export type IConvertVideoOptions = IOptions & { verb: string; audio: string; }; +export type { WatermarkOptions, LogoWatermarkOptions, TextWatermarkOptions } from './lib/media/images/watermark.js'; +export type { BackgroundRemoveOptions } from './lib/media/images/background-remove.js'; diff --git a/packages/media/docs/cli-background-remove.md b/packages/media/docs/cli-background-remove.md new file mode 100644 index 00000000..24304d9e --- /dev/null +++ b/packages/media/docs/cli-background-remove.md @@ -0,0 +1,638 @@ +# Background Remove CLI Documentation + +The `pm-media background:remove` command uses AI-powered background removal to automatically isolate subjects from their backgrounds. This tool leverages the [Replicate API](https://replicate.com/cjwbw/rembg) for high-quality results and supports batch processing with multiple AI models. + +## Table of Contents + +- [Installation](#installation) +- [Setup](#setup) +- [Basic Usage](#basic-usage) +- [AI Models](#ai-models) +- [Command Line Options](#command-line-options) +- [API Usage](#api-usage) +- [Examples](#examples) +- [Alpha Matting](#alpha-matting) +- [Performance Tips](#performance-tips) +- [Troubleshooting](#troubleshooting) + +## Installation + +```bash +npm install @polymech/media +``` + +## Setup + +### 1. Get Replicate API Key + +1. Visit [Replicate API Tokens](https://replicate.com/account/api-tokens) +2. Sign up or log in to your account +3. Create a new API token +4. Copy your API token + +### 2. Set API Key + +You can provide your API key in two ways: + +**Option A: Environment Variable (Recommended)** +```bash +export REPLICATE_API_TOKEN="your_api_token_here" +``` + +**Option B: Command Line Argument** +```bash +pm-media background:remove --src input.jpg --apiKey "your_api_token_here" +``` + +## Basic Usage + +```bash +pm-media background:remove --src --dst [options] +``` + +### Required Parameters + +- `--src`: Source files (FILE|FOLDER|GLOB pattern) + +### Optional Parameters + +- `--dst`: Destination path (defaults to source location with modified name) +- `--apiKey`: Replicate API key (if not set via environment variable) + +## AI Models + +The tool supports multiple specialized AI models for different use cases: + +### Available Models + +| Model | Best For | Description | +|-------|----------|-------------| +| `u2net` (default) | General use | Universal background removal | +| `u2netp` | Performance | Lighter version of U2Net | +| `u2net_human_seg` | People | Optimized for human subjects | +| `u2net_cloth_seg` | Clothing | Specialized for clothing items | +| `silueta` | Portraits | High-quality person silhouettes | + +### Model Selection + +```bash +# General purpose (default) +pm-media background:remove --src photo.jpg --model u2net + +# Optimized for people +pm-media background:remove --src portrait.jpg --model u2net_human_seg + +# Clothing/fashion +pm-media background:remove --src product.jpg --model u2net_cloth_seg +``` + +## Command Line Options + +### Core Options + +| Option | Type | Default | Description | +|--------|------|---------|-------------| +| `--src` | string | required | Source files (FILE\|FOLDER\|GLOB) | +| `--dst` | string | - | Destination path | +| `--apiKey` | string | - | Replicate API key | +| `--model` | choice | "u2net" | AI model to use | + +### Alpha Matting Options + +| Option | Type | Default | Description | +|--------|------|---------|-------------| +| `--alphaMattting` | boolean | false | Enable alpha matting for better edges | +| `--alphaMattingForegroundThreshold` | number | 270 | Foreground detection threshold | +| `--alphaMattingBackgroundThreshold` | number | 10 | Background detection threshold | +| `--alphaMattingErodeSize` | number | 10 | Edge erosion size | + +### Utility Options + +| Option | Type | Default | Description | +|--------|------|---------|-------------| +| `--dry` | boolean | false | Preview mode (no API calls) | +| `--verbose` | boolean | false | Show detailed processing info | +| `--debug` | boolean | false | Enable debug messages | +| `--logLevel` | string | "info" | Log level (warn\|info\|debug\|error) | + +## API Usage + +### Import the Library + +```typescript +import { + backgroundRemove, + removeBackgroundFile, + BackgroundRemoveOptions +} from '@polymech/media'; +``` + +### Single File Background Removal + +```typescript +import { removeBackgroundFile } from '@polymech/media'; + +await removeBackgroundFile( + 'input.jpg', + 'output.png', + { + apiKey: 'your_api_token', + model: 'u2net', + alpha_matting: false + } +); +``` + +### Batch Processing API + +```typescript +import { backgroundRemove } from '@polymech/media'; + +const options: BackgroundRemoveOptions = { + src: 'photos/*.jpg', + dst: 'no-bg/', + apiKey: process.env.REPLICATE_API_TOKEN, + model: 'u2net_human_seg', + alpha_matting: true, + // ... other IOptions +}; + +await backgroundRemove(options); +``` + +### Advanced Configuration + +```typescript +const advancedOptions: BackgroundRemoveOptions = { + src: 'portraits/*.jpg', + dst: 'processed/', + apiKey: 'your_token', + model: 'u2net_human_seg', + alpha_matting: true, + alpha_matting_foreground_threshold: 280, + alpha_matting_background_threshold: 15, + alpha_matting_erode_size: 8, + verbose: true +}; + +await backgroundRemove(advancedOptions); +``` + +## Examples + +### Example 1: Basic Background Removal + +```bash +# Remove background from a single image +pm-media background:remove \ + --src "photo.jpg" \ + --dst "no-background.png" +``` + +### Example 2: Batch Processing + +```bash +# Process multiple images +pm-media background:remove \ + --src "photos/*.jpg" \ + --dst "processed/" \ + --model u2net +``` + +### Example 3: Portrait Optimization + +```bash +# Optimized for people/portraits +pm-media background:remove \ + --src "portraits/*.jpg" \ + --dst "headshots/" \ + --model u2net_human_seg \ + --alphaMattting +``` + +### Example 4: Product Photography + +```bash +# E-commerce product images +pm-media background:remove \ + --src "products/*.jpg" \ + --dst "catalog/" \ + --model u2net_cloth_seg \ + --alphaMattting \ + --alphaMattingForegroundThreshold 280 +``` + +### Example 5: High-Quality Processing + +```bash +# Maximum quality with alpha matting +pm-media background:remove \ + --src "studio-photos/*.jpg" \ + --dst "final/" \ + --model silueta \ + --alphaMattting \ + --alphaMattingForegroundThreshold 300 \ + --alphaMattingBackgroundThreshold 5 \ + --verbose +``` + +### Example 6: Fast Batch Processing + +```bash +# Quick processing for previews +pm-media background:remove \ + --src "batch/*.jpg" \ + --dst "previews/" \ + --model u2netp +``` + +### Example 7: Dry Run Preview + +```bash +# Preview what would be processed +pm-media background:remove \ + --src "archive/**/*.jpg" \ + --dst "processed/" \ + --dry \ + --verbose +``` + +### Example 8: Organized Output + +```bash +# Maintain folder structure +pm-media background:remove \ + --src "organized/session-1/*.jpg" \ + --dst "no-bg/session-1/" \ + --model u2net_human_seg +``` + +## Alpha Matting + +Alpha matting provides superior edge quality for complex subjects with fine details like hair, fur, or transparent materials. + +### When to Use Alpha Matting + +āœ… **Use alpha matting for:** +- Portraits with detailed hair +- Furry animals +- Objects with fine edges +- Semi-transparent materials +- Professional/commercial work + +āŒ **Skip alpha matting for:** +- Simple shapes +- Hard edges +- Quick previews +- Batch processing (slower) + +### Alpha Matting Parameters + +```bash +# Standard alpha matting +pm-media background:remove \ + --src input.jpg \ + --dst output.png \ + --alphaMattting + +# Fine-tuned alpha matting +pm-media background:remove \ + --src portrait.jpg \ + --dst result.png \ + --alphaMattting \ + --alphaMattingForegroundThreshold 280 \ + --alphaMattingBackgroundThreshold 12 \ + --alphaMattingErodeSize 6 +``` + +### Parameter Guidelines + +| Parameter | Low Value | High Value | Effect | +|-----------|-----------|------------|--------| +| Foreground Threshold | 200 | 350 | More/less foreground detection | +| Background Threshold | 5 | 20 | More/less background detection | +| Erode Size | 3 | 15 | Smaller/larger edge refinement | + +## File Format Support + +### Supported Input Formats +- JPEG (.jpg, .jpeg) +- PNG (.png) +- WebP (.webp) +- TIFF (.tiff, .tif) + +### Output Format +- **PNG with transparency** (recommended) +- Automatically adds transparency channel +- Preserves original quality + +### Format Recommendations + +```bash +# For web use +pm-media background:remove --src input.jpg --dst output.png + +# For print/professional +pm-media background:remove --src input.tiff --dst output.png --alphaMattting +``` + +## Performance Tips + +### 1. Choose Appropriate Models + +```bash +# Fast processing +--model u2netp + +# Balanced quality/speed +--model u2net + +# High quality (slower) +--model silueta +``` + +### 2. Use Alpha Matting Selectively + +```bash +# For most images (faster) +pm-media background:remove --src batch/*.jpg --dst output/ + +# For detailed work only (slower) +pm-media background:remove --src detailed/*.jpg --dst output/ --alphaMattting +``` + +### 3. Batch Processing Strategies + +```bash +# Process in chunks for large batches +pm-media background:remove --src "batch1/*.jpg" --dst "output1/" +pm-media background:remove --src "batch2/*.jpg" --dst "output2/" +``` + +### 4. API Rate Limiting + +The Replicate API has rate limits. For large batches: +- Process during off-peak hours +- Consider parallel processing limits +- Monitor API usage in your Replicate dashboard + +## Cost Considerations + +### Replicate Pricing + +Background removal costs per prediction. Check current pricing at [Replicate Pricing](https://replicate.com/pricing). + +### Cost Optimization + +```bash +# Test with dry run first +pm-media background:remove --src "*.jpg" --dst "output/" --dry + +# Use efficient models +--model u2netp # Fastest/cheapest +--model u2net # Balanced +--model silueta # Highest quality/most expensive +``` + +## Troubleshooting + +### Common Issues + +#### "API key is required" +```bash +# Set environment variable +export REPLICATE_API_TOKEN="your_token" + +# Or use command line +pm-media background:remove --src input.jpg --apiKey "your_token" +``` + +#### "Replicate package not found" +```bash +# Install missing dependency +npm install replicate +``` + +#### Poor edge quality +```bash +# Enable alpha matting +pm-media background:remove \ + --src input.jpg \ + --dst output.png \ + --alphaMattting \ + --alphaMattingForegroundThreshold 280 +``` + +#### API rate limit errors +- Reduce batch size +- Add delays between requests +- Check your Replicate dashboard for limits + +#### Large file processing fails +- Resize images before processing +- Use appropriate model for image type +- Check API payload limits + +### Debug Mode + +Enable detailed logging: + +```bash +pm-media background:remove \ + --src "input/*" \ + --dst "output/" \ + --debug \ + --verbose +``` + +### Quality Issues + +```bash +# For people/portraits +--model u2net_human_seg + +# For products/objects +--model u2net_cloth_seg + +# For complex edges +--alphaMattting --alphaMattingForegroundThreshold 300 +``` + +## Integration Examples + +### E-commerce Workflow + +```bash +#!/bin/bash +# Product photography pipeline + +INPUT_DIR="$1" +OUTPUT_DIR="$2" + +# Remove backgrounds +pm-media background:remove \ + --src "$INPUT_DIR/*.jpg" \ + --dst "$OUTPUT_DIR/no-bg/" \ + --model u2net_cloth_seg \ + --alphaMattting + +# Create thumbnails +pm-media resize \ + --src "$OUTPUT_DIR/no-bg/*.png" \ + --dst "$OUTPUT_DIR/thumbs/" \ + --width 300 \ + --height 300 \ + --fit contain \ + --background white +``` + +### Portrait Studio Workflow + +```bash +#!/bin/bash +# Professional portrait processing + +pm-media background:remove \ + --src "portraits/*.jpg" \ + --dst "processed/" \ + --model u2net_human_seg \ + --alphaMattting \ + --alphaMattingForegroundThreshold 290 \ + --verbose + +echo "Background removal complete" +``` + +### Batch Organization Script + +```bash +#!/bin/bash +# Organize processed images + +for dir in */; do + if [ -d "$dir" ]; then + echo "Processing directory: $dir" + pm-media background:remove \ + --src "$dir*.jpg" \ + --dst "no-bg/$dir" \ + --model u2net \ + --verbose + fi +done +``` + +## Advanced Usage + +### Environment Configuration + +```bash +# .env file +REPLICATE_API_TOKEN=your_token_here +DEFAULT_BG_MODEL=u2net_human_seg +ALPHA_MATTING=true + +# Use in scripts +pm-media background:remove \ + --src "*.jpg" \ + --dst "output/" \ + --model "$DEFAULT_BG_MODEL" +``` + +### Quality Control + +```bash +#!/bin/bash +# Process with multiple quality levels + +INPUT="$1" +BASE_NAME=$(basename "$INPUT" .jpg) + +# Quick preview +pm-media background:remove \ + --src "$INPUT" \ + --dst "preview/${BASE_NAME}_preview.png" \ + --model u2netp + +# High quality +pm-media background:remove \ + --src "$INPUT" \ + --dst "final/${BASE_NAME}_final.png" \ + --model silueta \ + --alphaMattting +``` + +### Conditional Processing + +```bash +#!/bin/bash +# Different models based on file type + +for image in *.jpg; do + if [[ $image == *"portrait"* ]]; then + MODEL="u2net_human_seg" + elif [[ $image == *"product"* ]]; then + MODEL="u2net_cloth_seg" + else + MODEL="u2net" + fi + + pm-media background:remove \ + --src "$image" \ + --dst "processed/" \ + --model "$MODEL" +done +``` + +## TypeScript Definitions + +```typescript +interface BackgroundRemoveOptions extends IOptions { + apiKey?: string; + model?: 'u2net' | 'u2netp' | 'u2net_human_seg' | 'u2net_cloth_seg' | 'silueta'; + alpha_matting?: boolean; + alpha_matting_foreground_threshold?: number; + alpha_matting_background_threshold?: number; + alpha_matting_erode_size?: number; +} + +declare function removeBackgroundFile( + inputPath: string, + outputPath: string, + options: BackgroundRemoveOptions +): Promise; + +declare function backgroundRemove( + options: BackgroundRemoveOptions +): Promise; +``` + +## Security Notes + +### API Key Security + +- Never commit API keys to version control +- Use environment variables in production +- Rotate keys regularly +- Monitor usage in Replicate dashboard + +### File Handling + +- Validate input file types +- Check file sizes before processing +- Sanitize file paths +- Handle temporary files securely + +## Contributing + +For bug reports, feature requests, or contributions, please visit the project repository. + +## References + +- [Replicate API Documentation](https://replicate.com/docs) +- [rembg Model on Replicate](https://replicate.com/cjwbw/rembg) +- [Replicate Pricing](https://replicate.com/pricing) +- [API Rate Limits](https://replicate.com/docs/reference/http#rate-limits) + +## License + +This tool is part of the @polymech/media package. Please refer to the package license for usage terms. diff --git a/packages/media/docs/cli-pdf2jpg.md b/packages/media/docs/cli-pdf2jpg.md new file mode 100644 index 00000000..446a9108 --- /dev/null +++ b/packages/media/docs/cli-pdf2jpg.md @@ -0,0 +1,532 @@ +# PDF2JPG CLI Documentation + +The `pm-media pdf2jpg` command converts PDF documents to high-quality images (JPG or PNG). This tool supports batch processing, custom DPI settings, page range selection, and advanced rendering options using MuPDF. + +## Table of Contents + +- [Installation](#installation) +- [Basic Usage](#basic-usage) +- [Output Formats](#output-formats) +- [Command Line Options](#command-line-options) +- [API Usage](#api-usage) +- [Examples](#examples) +- [Template Variables](#template-variables) +- [Performance Optimization](#performance-optimization) +- [Troubleshooting](#troubleshooting) + +## Installation + +```bash +npm install @polymech/media +``` + +## Basic Usage + +```bash +pm-media pdf2jpg --input [options] +``` + +### Required Parameters + +- `--input` (or `-i`): Path to the input PDF file + +### Optional Parameters + +- `--output` (or `-o`): Output path template +- `--dpi`: Resolution for output images (default: 300) +- `--format`: Output format - 'jpg' or 'png' (default: 'jpg') +- `--scale`: Scaling factor (default: 2) +- `--startPage`: First page to convert (1-based) +- `--endPage`: Last page to convert (1-based) + +## Output Formats + +### JPEG Format +- **Extension**: `.jpg` +- **Use case**: Photographs, complex images +- **Pros**: Smaller file sizes, good compression +- **Cons**: Lossy compression, no transparency + +### PNG Format +- **Extension**: `.png` +- **Use case**: Text, diagrams, images with transparency +- **Pros**: Lossless compression, transparency support +- **Cons**: Larger file sizes + +## Command Line Options + +### Core Options + +| Option | Alias | Type | Default | Description | +|--------|-------|------|---------|-------------| +| `--input` | `-i` | string | required | Path to the input PDF file | +| `--output` | `-o` | string | auto | Output path template | +| `--dpi` | - | number | 300 | Resolution for output images | +| `--format` | - | choice | 'jpg' | Output format: 'jpg' or 'png' | +| `--scale` | - | number | 2 | Scaling factor for rendering | + +### Page Range Options + +| Option | Type | Description | +|--------|------|-------------| +| `--startPage` | number | First page to convert (1-based index) | +| `--endPage` | number | Last page to convert (1-based index) | + +### Quality & Performance + +| Option | Type | Default | Description | +|--------|------|---------|-------------| +| `--dpi` | number | 300 | Higher = better quality, larger files | +| `--scale` | number | 2 | Rendering scale factor | + +## API Usage + +### Import the Library + +```typescript +import { + runConversion, + convertPdfToImages, + ConvertCommandConfig, + ImageFormat +} from '@polymech/media'; +``` + +### Single PDF Conversion + +```typescript +import { runConversion } from '@polymech/media'; +import { logger } from 'tslog'; + +const config: ConvertCommandConfig = { + input: 'document.pdf', + output: 'output/page_{PAGE}.jpg', + dpi: 300, + format: 'jpg', + scale: 2 +}; + +const outputFiles = await runConversion(config, logger); +console.log(`Generated ${outputFiles.length} images`); +``` + +### Advanced PDF Conversion + +```typescript +import { convertPdfToImages } from '@polymech/media'; +import { readFile } from 'fs/promises'; + +const pdfBuffer = await readFile('document.pdf'); + +const options = { + baseVariables: { + SRC_NAME: 'document', + SRC_DIR: '/output' + }, + outputPathTemplate: '${SRC_DIR}/${SRC_NAME}_${PAGE}.${FORMAT}', + dpi: 600, + scale: 1.5, + format: 'png' as ImageFormat, + startPage: 1, + endPage: 10 +}; + +const outputFiles = await convertPdfToImages(pdfBuffer, options); +``` + +### Custom Page Range + +```typescript +const config: ConvertCommandConfig = { + input: 'large-document.pdf', + output: 'pages/chapter_{PAGE}.png', + format: 'png', + startPage: 10, + endPage: 25, + dpi: 150 // Lower DPI for faster processing +}; + +await runConversion(config, logger); +``` + +## Examples + +### Example 1: Basic PDF to JPG + +```bash +# Convert entire PDF to JPG images +pm-media pdf2jpg \ + --input "document.pdf" \ + --output "images/page_{PAGE}.jpg" +``` + +### Example 2: High-Quality PNG Conversion + +```bash +# High-quality PNG conversion +pm-media pdf2jpg \ + --input "technical-manual.pdf" \ + --output "manual/page_{PAGE}.png" \ + --format png \ + --dpi 600 \ + --scale 1 +``` + +### Example 3: Specific Page Range + +```bash +# Convert only pages 5-15 +pm-media pdf2jpg \ + --input "book.pdf" \ + --output "chapter/page_{PAGE}.jpg" \ + --startPage 5 \ + --endPage 15 \ + --dpi 300 +``` + +### Example 4: Fast Preview Generation + +```bash +# Low-quality previews for quick processing +pm-media pdf2jpg \ + --input "presentation.pdf" \ + --output "previews/slide_{PAGE}.jpg" \ + --dpi 150 \ + --scale 1 +``` + +### Example 5: Print-Quality Images + +```bash +# Print-quality conversion +pm-media pdf2jpg \ + --input "brochure.pdf" \ + --output "print-ready/page_{PAGE}.png" \ + --format png \ + --dpi 600 \ + --scale 2 +``` + +### Example 6: Organized Output Structure + +```bash +# Organized folder structure +pm-media pdf2jpg \ + --input "reports/quarterly-report.pdf" \ + --output "output/quarterly/{PAGE:03d}_page.jpg" \ + --dpi 300 +``` + +### Example 7: Single Page Extraction + +```bash +# Extract just the first page +pm-media pdf2jpg \ + --input "document.pdf" \ + --output "cover.jpg" \ + --startPage 1 \ + --endPage 1 \ + --dpi 300 +``` + +### Example 8: Batch Processing Script + +```bash +#!/bin/bash +# Process multiple PDFs + +for pdf in *.pdf; do + name=$(basename "$pdf" .pdf) + pm-media pdf2jpg \ + --input "$pdf" \ + --output "converted/${name}/{PAGE}.jpg" \ + --dpi 300 \ + --format jpg +done +``` + +## Template Variables + +The output path supports template variables for dynamic naming: + +### Available Variables + +| Variable | Description | Example | +|----------|-------------|---------| +| `{PAGE}` | Page number | `1`, `2`, `3` | +| `{PAGE:03d}` | Zero-padded page | `001`, `002`, `003` | +| `{SRC_NAME}` | PDF filename (no extension) | `document` | +| `{SRC_DIR}` | Source directory | `/path/to/source` | +| `{FORMAT}` | Output format | `jpg`, `png` | + +### Template Examples + +```bash +# Basic template +--output "pages/page_{PAGE}.jpg" +# Result: pages/page_1.jpg, pages/page_2.jpg + +# Zero-padded pages +--output "output/{PAGE:03d}_page.{FORMAT}" +# Result: output/001_page.jpg, output/002_page.jpg + +# Include source name +--output "{SRC_NAME}/page_{PAGE}.{FORMAT}" +# Result: document/page_1.jpg, document/page_2.jpg + +# Complex structure +--output "converted/{SRC_NAME}/{PAGE:04d}_{SRC_NAME}.{FORMAT}" +# Result: converted/manual/0001_manual.jpg +``` + +## DPI and Quality Guidelines + +### DPI Recommendations + +| Use Case | DPI | File Size | Quality | +|----------|-----|-----------|---------| +| Web preview | 72-96 | Small | Basic | +| Screen viewing | 150 | Medium | Good | +| Standard print | 300 | Large | High | +| Professional print | 600+ | Very large | Excellent | + +### Quality vs Performance + +```bash +# Fast processing (previews) +pm-media pdf2jpg --input doc.pdf --dpi 150 --scale 1 + +# Balanced (general use) +pm-media pdf2jpg --input doc.pdf --dpi 300 --scale 2 + +# High quality (print/archive) +pm-media pdf2jpg --input doc.pdf --dpi 600 --scale 1 --format png +``` + +## Performance Optimization + +### 1. Adjust DPI for Use Case + +```bash +# Thumbnails/previews +pm-media pdf2jpg --input large.pdf --dpi 96 --output "thumbs/{PAGE}.jpg" + +# Print quality +pm-media pdf2jpg --input doc.pdf --dpi 300 --output "print/{PAGE}.png" +``` + +### 2. Use Appropriate Format + +```bash +# Photos/complex images → JPG +pm-media pdf2jpg --input photo-catalog.pdf --format jpg --dpi 300 + +# Text/diagrams → PNG +pm-media pdf2jpg --input technical-docs.pdf --format png --dpi 300 +``` + +### 3. Process Page Ranges + +```bash +# Process in chunks for large PDFs +pm-media pdf2jpg --input huge.pdf --startPage 1 --endPage 50 --output "batch1/{PAGE}.jpg" +pm-media pdf2jpg --input huge.pdf --startPage 51 --endPage 100 --output "batch2/{PAGE}.jpg" +``` + +### 4. Scale Factor Optimization + +```bash +# Scale = 1 for faster processing +pm-media pdf2jpg --input doc.pdf --scale 1 --dpi 300 + +# Scale = 2 for better quality (default) +pm-media pdf2jpg --input doc.pdf --scale 2 --dpi 300 +``` + +## File Organization + +### Automatic Directory Creation + +The tool automatically creates output directories: + +```bash +# Creates nested directories as needed +pm-media pdf2jpg \ + --input "doc.pdf" \ + --output "output/projects/client-a/pages/{PAGE}.jpg" +``` + +### Organized Output Patterns + +```bash +# By document name +--output "{SRC_NAME}/page_{PAGE:03d}.jpg" + +# By date and document +--output "$(date +%Y-%m-%d)/{SRC_NAME}/{PAGE}.jpg" + +# By quality level +--output "high-res/{SRC_NAME}/page_{PAGE}.png" +``` + +## Troubleshooting + +### Common Issues + +#### "Input file does not exist" +```bash +# Check file path and permissions +ls -la path/to/file.pdf +pm-media pdf2jpg --input "./document.pdf" --output "output/{PAGE}.jpg" +``` + +#### "Unable to open PDF" +- Ensure PDF is not corrupted +- Check if PDF is password-protected +- Verify file permissions + +#### Poor image quality +```bash +# Increase DPI and use PNG for text +pm-media pdf2jpg \ + --input doc.pdf \ + --format png \ + --dpi 600 \ + --scale 1 +``` + +#### Large file sizes +```bash +# Reduce DPI or use JPG format +pm-media pdf2jpg \ + --input doc.pdf \ + --format jpg \ + --dpi 300 \ + --scale 1 +``` + +#### Memory issues with large PDFs +```bash +# Process in smaller page ranges +pm-media pdf2jpg --input large.pdf --startPage 1 --endPage 10 +pm-media pdf2jpg --input large.pdf --startPage 11 --endPage 20 +``` + +### Debug Mode + +No specific debug mode, but check output for errors: + +```bash +pm-media pdf2jpg --input doc.pdf --output "{PAGE}.jpg" 2>&1 | tee conversion.log +``` + +### Page Range Validation + +```bash +# Check PDF page count first +pm-media pdf2jpg --input doc.pdf --startPage 1 --endPage 1 # Test first page +``` + +## Advanced Usage + +### Integration with Other Tools + +```bash +#!/bin/bash +# Convert PDF and create thumbnails + +PDF_FILE="$1" +BASE_NAME=$(basename "$PDF_FILE" .pdf) + +# Convert to high-res images +pm-media pdf2jpg \ + --input "$PDF_FILE" \ + --output "images/${BASE_NAME}/{PAGE:03d}.png" \ + --format png \ + --dpi 300 + +# Create thumbnails +pm-media resize \ + --src "images/${BASE_NAME}/*.png" \ + --dst "thumbnails/${BASE_NAME}/" \ + --width 200 \ + --height 200 \ + --fit cover +``` + +### Automation Scripts + +```bash +#!/bin/bash +# Automated PDF processing pipeline + +INPUT_DIR="$1" +OUTPUT_DIR="$2" + +find "$INPUT_DIR" -name "*.pdf" | while read pdf; do + name=$(basename "$pdf" .pdf) + echo "Processing: $pdf" + + pm-media pdf2jpg \ + --input "$pdf" \ + --output "$OUTPUT_DIR/$name/{PAGE:03d}.jpg" \ + --dpi 300 \ + --format jpg + + echo "Completed: $name" +done +``` + +### Quality Control + +```bash +#!/bin/bash +# Generate multiple quality versions + +PDF="$1" +NAME=$(basename "$PDF" .pdf) + +# Preview quality +pm-media pdf2jpg --input "$PDF" --output "preview/$NAME/{PAGE}.jpg" --dpi 150 + +# Standard quality +pm-media pdf2jpg --input "$PDF" --output "standard/$NAME/{PAGE}.jpg" --dpi 300 + +# Print quality +pm-media pdf2jpg --input "$PDF" --output "print/$NAME/{PAGE}.png" --dpi 600 --format png +``` + +## TypeScript Definitions + +```typescript +interface ConvertCommandConfig { + input: string; + output?: string; + dpi: number; + scale?: number; + format: 'png' | 'jpg'; + startPage?: number; + endPage?: number; +} + +interface PdfToImageOptions { + baseVariables: Record; + outputPathTemplate: string; + dpi: number; + scale?: number; + format: ImageFormat; + startPage?: number; + endPage?: number; + logger?: Logger; +} + +type ImageFormat = 'png' | 'jpg'; +``` + +## Contributing + +For bug reports, feature requests, or contributions, please visit the project repository. + +## License + +This tool is part of the @polymech/media package. Please refer to the package license for usage terms. diff --git a/packages/media/docs/cli-resize.md b/packages/media/docs/cli-resize.md new file mode 100644 index 00000000..b38191ba --- /dev/null +++ b/packages/media/docs/cli-resize.md @@ -0,0 +1,545 @@ +# Resize CLI Documentation + +The `pm-media resize` command allows you to resize images with precise control over dimensions, quality, and performance. This tool supports batch processing and offers extensive options for scaling, cropping, and format conversion. + +## Table of Contents + +- [Installation](#installation) +- [Basic Usage](#basic-usage) +- [Resize Methods](#resize-methods) +- [Command Line Options](#command-line-options) +- [API Usage](#api-usage) +- [Examples](#examples) +- [Performance Options](#performance-options) +- [Troubleshooting](#troubleshooting) + +## Installation + +```bash +npm install @polymech/media +``` + +## Basic Usage + +```bash +pm-media resize --src --dst [resize-options] +``` + +### Required Parameters + +- `--src`: Source files (FILE|FOLDER|GLOB pattern) + +### Optional Parameters + +- `--dst`: Destination path (defaults to source location) + +## Resize Methods + +### 1. Percentage-based Resizing + +Resize images by a percentage of their original size: + +```bash +pm-media resize \ + --src "photos/*.jpg" \ + --dst "thumbnails/" \ + --percent 50 +``` + +### 2. Fixed Width/Height + +Resize to specific dimensions: + +```bash +pm-media resize \ + --src "photos/*.jpg" \ + --dst "resized/" \ + --width 800 \ + --height 600 +``` + +### 3. Width-only or Height-only + +Maintain aspect ratio with one dimension: + +```bash +# Resize to 1920px width, auto height +pm-media resize \ + --src "photos/*.jpg" \ + --dst "web/" \ + --width 1920 + +# Resize to 1080px height, auto width +pm-media resize \ + --src "photos/*.jpg" \ + --dst "web/" \ + --height 1080 +``` + +## Command Line Options + +### Resize Dimensions + +| Option | Type | Default | Description | +|--------|------|---------|-------------| +| `--width` | number | - | Target width in pixels | +| `--height` | number | - | Target height in pixels | +| `--percent` | number | - | Resize by percentage (1-100) | + +### Minimum Size Constraints + +| Option | Type | Default | Description | +|--------|------|---------|-------------| +| `--minWidth` | number | - | Don't resize if width below this value | +| `--minHeight` | number | - | Don't resize if height below this value | +| `--minSize` | number | - | Don't resize if file size below this (bytes) | + +### Sharp-specific Options + +| Option | Type | Default | Description | +|--------|------|---------|-------------| +| `--fit` | string | 'cover' | How to fit: cover, contain, fill, inside, outside | +| `--position` | string | 'centre' | Position when using fit: top, bottom, left, right, etc | +| `--background` | string | 'white' | Background color for contain/letterbox | +| `--withoutEnlargement` | boolean | false | Don't enlarge smaller images | +| `--withoutReduction` | boolean | false | Don't reduce larger images | +| `--fastShrinkOnLoad` | boolean | true | Use JPEG/WebP shrink-on-load | + +### Common Options + +| Option | Type | Default | Description | +|--------|------|---------|-------------| +| `--src` | string | required | Source files (FILE\|FOLDER\|GLOB) | +| `--dst` | string | - | Destination path | +| `--dry` | boolean | false | Preview mode (no files written) | +| `--verbose` | boolean | false | Show detailed processing info | +| `--debug` | boolean | false | Enable debug messages | +| `--logLevel` | string | "info" | Log level (warn\|info\|debug\|error) | + +## API Usage + +### Import the Library + +```typescript +import { + resize, + resizeFile, + IResizeOptions +} from '@polymech/media'; +``` + +### Single File Resize + +```typescript +import { resizeFile } from '@polymech/media'; + +// Resize by percentage +await resizeFile( + 'input.jpg', + 'output.jpg', + () => {}, // onNode callback + { + percent: 50, + logLevel: 'info' + } +); + +// Resize to specific dimensions +await resizeFile( + 'input.jpg', + 'thumbnail.jpg', + () => {}, + { + width: 300, + height: 300, + fit: 'cover', + withoutEnlargement: true + } +); +``` + +### Batch Resize API + +```typescript +import { resize } from '@polymech/media'; + +const options: IResizeOptions = { + src: 'photos/*.jpg', + dst: 'resized/', + width: 1920, + height: 1080, + fit: 'inside', + withoutEnlargement: true, + // ... other IOptions +}; + +const results = await resize(options); +``` + +### Advanced Resize Options + +```typescript +const advancedOptions: IResizeOptions = { + src: 'raw/*.tiff', + dst: 'processed/', + width: 2048, + height: 1536, + fit: 'cover', + position: 'center', + background: { r: 255, g: 255, b: 255, alpha: 1 }, + withoutEnlargement: true, + fastShrinkOnLoad: true, + kernel: 'lanczos3' +}; +``` + +## Examples + +### Example 1: Create Thumbnails + +```bash +# Generate 150px square thumbnails +pm-media resize \ + --src "gallery/*.jpg" \ + --dst "thumbs/" \ + --width 150 \ + --height 150 \ + --fit cover \ + --withoutEnlargement +``` + +### Example 2: Web Optimization + +```bash +# Optimize for web (max 1920px width) +pm-media resize \ + --src "photos/*.jpg" \ + --dst "web-optimized/" \ + --width 1920 \ + --minWidth 800 \ + --fit inside \ + --withoutEnlargement +``` + +### Example 3: Percentage-based Batch Resize + +```bash +# Reduce all images to 75% of original size +pm-media resize \ + --src "archive/**/*.{jpg,png}" \ + --dst "compressed/" \ + --percent 75 +``` + +### Example 4: Social Media Formats + +```bash +# Instagram square format (1080x1080) +pm-media resize \ + --src "photos/*.jpg" \ + --dst "instagram/" \ + --width 1080 \ + --height 1080 \ + --fit cover \ + --position center + +# Twitter header (1500x500) +pm-media resize \ + --src "headers/*.jpg" \ + --dst "twitter/" \ + --width 1500 \ + --height 500 \ + --fit cover +``` + +### Example 5: Preserve Small Images + +```bash +# Don't resize images smaller than 500px width +pm-media resize \ + --src "mixed/*.jpg" \ + --dst "standardized/" \ + --width 1200 \ + --minWidth 500 \ + --withoutEnlargement +``` + +### Example 6: File Size Based Resize + +```bash +# Only resize files larger than 2MB +pm-media resize \ + --src "large/*.jpg" \ + --dst "optimized/" \ + --percent 60 \ + --minSize 2097152 +``` + +### Example 7: Format Conversion with Resize + +```bash +# Resize and convert to WebP +pm-media resize \ + --src "photos/*.jpg" \ + --dst "webp/{SRC_NAME}.webp" \ + --width 1920 \ + --fit inside +``` + +## Fit Options Explained + +### `cover` (default) +- Crop to fill exact dimensions +- Maintains aspect ratio +- May crop parts of the image + +```bash +pm-media resize --src input.jpg --dst output.jpg --width 800 --height 600 --fit cover +``` + +### `contain` +- Letterbox to fit within dimensions +- Maintains aspect ratio +- No cropping, adds background + +```bash +pm-media resize --src input.jpg --dst output.jpg --width 800 --height 600 --fit contain --background white +``` + +### `fill` +- Stretch to exact dimensions +- Does not maintain aspect ratio +- No cropping + +```bash +pm-media resize --src input.jpg --dst output.jpg --width 800 --height 600 --fit fill +``` + +### `inside` +- Resize to fit within dimensions +- Maintains aspect ratio +- May result in smaller dimensions + +```bash +pm-media resize --src input.jpg --dst output.jpg --width 800 --height 600 --fit inside +``` + +### `outside` +- Resize to cover dimensions +- Maintains aspect ratio +- May result in larger dimensions + +```bash +pm-media resize --src input.jpg --dst output.jpg --width 800 --height 600 --fit outside +``` + +## Position Options + +When using `fit: cover` or `fit: contain`, control crop/letterbox position: + +- `center` (default) +- `top`, `bottom`, `left`, `right` +- `top left`, `top right`, `bottom left`, `bottom right` +- `north`, `south`, `east`, `west` +- `northeast`, `northwest`, `southeast`, `southwest` + +```bash +pm-media resize \ + --src portrait.jpg \ + --dst cropped.jpg \ + --width 800 \ + --height 600 \ + --fit cover \ + --position "top center" +``` + +## File Format Support + +### Supported Input Formats +- JPEG (.jpg, .jpeg) +- PNG (.png) +- WebP (.webp) +- TIFF (.tiff, .tif) +- AVIF (.avif) +- SVG (.svg) - rasterized +- GIF (.gif) - first frame + +### Supported Output Formats +Output format determined by destination file extension: +- `.jpg`, `.jpeg` → JPEG +- `.png` → PNG +- `.webp` → WebP +- `.tiff`, `.tif` → TIFF +- `.avif` → AVIF + +## Performance Tips + +### 1. Fast Shrink-on-Load +```bash +# Use JPEG/WebP built-in scaling (faster for large reductions) +pm-media resize \ + --src "huge/*.jpg" \ + --dst "thumbnails/" \ + --width 300 \ + --fastShrinkOnLoad +``` + +### 2. Batch Processing +```bash +# Process multiple files efficiently +pm-media resize --src "batch/*.jpg" --dst "output/" --percent 50 +``` + +### 3. Prevent Unnecessary Enlargement +```bash +# Don't enlarge small images (saves processing time) +pm-media resize \ + --src "mixed/*.jpg" \ + --dst "standardized/" \ + --width 1920 \ + --withoutEnlargement +``` + +### 4. Size-based Processing +```bash +# Only process large files +pm-media resize \ + --src "photos/*.jpg" \ + --dst "compressed/" \ + --percent 70 \ + --minSize 1048576 # 1MB minimum +``` + +## Troubleshooting + +### Common Issues + +#### Images appear distorted +```bash +# Maintain aspect ratio with 'inside' or 'cover' +pm-media resize --src input.jpg --dst output.jpg --width 800 --height 600 --fit inside +``` + +#### Small images getting enlarged +```bash +# Prevent enlargement +pm-media resize --src input.jpg --dst output.jpg --width 1920 --withoutEnlargement +``` + +#### Poor quality on large reductions +```bash +# Use better kernel for quality +pm-media resize --src input.jpg --dst output.jpg --percent 25 --kernel lanczos3 +``` + +#### Memory issues with large files +```bash +# Use fast shrink for initial reduction +pm-media resize --src huge.jpg --dst smaller.jpg --percent 50 --fastShrinkOnLoad +``` + +### Debug Mode + +Enable detailed logging: + +```bash +pm-media resize \ + --src "input/*" \ + --dst "output/" \ + --width 800 \ + --debug \ + --verbose +``` + +### File Permissions + +Ensure you have: +- Read access to source files +- Write access to destination directory +- Sufficient disk space for output files + +## Advanced Usage + +### Template Variables + +Use template variables in destination paths: + +```bash +# Use source filename in destination +pm-media resize \ + --src "photos/*.jpg" \ + --dst "resized/{SRC_NAME}_resized.jpg" \ + --width 1200 +``` + +Available variables: +- `{SRC_NAME}`: Source filename without extension +- `{SRC_EXT}`: Source file extension +- `{SRC_DIR}`: Source directory + +### Integration Scripts + +```bash +#!/bin/bash +# Multi-size generation script + +SIZES=(300 600 1200 1920) +INPUT_DIR="$1" +OUTPUT_BASE="$2" + +for size in "${SIZES[@]}"; do + pm-media resize \ + --src "$INPUT_DIR/*.jpg" \ + --dst "$OUTPUT_BASE/${size}px/" \ + --width $size \ + --withoutEnlargement \ + --fit inside +done +``` + +### Conditional Processing + +```bash +#!/bin/bash +# Only resize if source is larger than target + +if [ -f "$1" ]; then + pm-media resize \ + --src "$1" \ + --dst "$2" \ + --width 1920 \ + --minWidth 1920 \ + --withoutEnlargement +fi +``` + +## TypeScript Definitions + +```typescript +interface IResizeOptionsSharp { + width?: number; + height?: number; + fit?: keyof sharp.FitEnum; + position?: number | string; + background?: sharp.Color; + kernel?: keyof sharp.KernelEnum; + withoutEnlargement?: boolean; + withoutReduction?: boolean; + fastShrinkOnLoad?: boolean; +} + +interface IResizeOptions extends IOptions, IResizeOptionsSharp { + percent?: number; + minWidth?: number; + minHeight?: number; + minSize?: number; +} +``` + +## Contributing + +For bug reports, feature requests, or contributions, please visit the project repository. + +## License + +This tool is part of the @polymech/media package. Please refer to the package license for usage terms. diff --git a/packages/media/docs/cli-watermark.md b/packages/media/docs/cli-watermark.md new file mode 100644 index 00000000..b298c6cb --- /dev/null +++ b/packages/media/docs/cli-watermark.md @@ -0,0 +1,446 @@ +# Watermark CLI Documentation + +The `pm-media watermark` command allows you to add watermarks to images using either text or image overlays. This tool supports batch processing and offers extensive customization options for positioning, styling, and opacity. + +## Table of Contents + +- [Installation](#installation) +- [Basic Usage](#basic-usage) +- [Text Watermarks](#text-watermarks) +- [Image Watermarks](#image-watermarks) +- [Command Line Options](#command-line-options) +- [API Usage](#api-usage) +- [Examples](#examples) +- [Troubleshooting](#troubleshooting) + +## Installation + +```bash +npm install @polymech/media +``` + +## Basic Usage + +```bash +pm-media watermark --src --dst --watermarkType [options] +``` + +### Required Parameters + +- `--src`: Source files (FILE|FOLDER|GLOB pattern) +- `--watermarkType`: Type of watermark (`text` or `image`) + +### Conditional Requirements + +- For text watermarks: `--text` is required +- For image watermarks: `--logoPath` is required + +## Text Watermarks + +Add text overlays to your images with full typography control. + +### Basic Text Watermark + +```bash +pm-media watermark \ + --src "photos/*.jpg" \ + --dst "output/" \ + --watermarkType text \ + --text "Ā© 2024 MyBrand" +``` + +### Advanced Text Styling + +```bash +pm-media watermark \ + --src "photos/*.jpg" \ + --dst "output/" \ + --watermarkType text \ + --text "Ā© 2024 MyBrand" \ + --position bottom-right \ + --fontSize 42 \ + --color "#ffffff" \ + --fontFamily "Arial" \ + --strokeColor "#000000" \ + --strokeWidth 3 \ + --opacity 0.9 \ + --margin 30 +``` + +### Text Watermark Options + +| Option | Type | Default | Description | +|--------|------|---------|-------------| +| `--text` | string | required | Text to display as watermark | +| `--fontSize` | number | 48 | Font size in pixels | +| `--color` | string | "#ffffff" | Text color (hex format) | +| `--fontFamily` | string | "Arial" | Font family name | +| `--strokeColor` | string | "#000000" | Text outline color (hex format) | +| `--strokeWidth` | number | 2 | Text outline width in pixels | + +## Image Watermarks + +Add logo or image overlays with automatic scaling and positioning. + +### Basic Image Watermark + +```bash +pm-media watermark \ + --src "photos/*.jpg" \ + --dst "output/" \ + --watermarkType image \ + --logoPath "logo.png" +``` + +### Advanced Image Positioning + +```bash +pm-media watermark \ + --src "photos/*.jpg" \ + --dst "output/" \ + --watermarkType image \ + --logoPath "watermark.png" \ + --position top-left \ + --sizePct 0.15 \ + --opacity 0.7 \ + --margin 20 +``` + +### Image Watermark Options + +| Option | Type | Default | Description | +|--------|------|---------|-------------| +| `--logoPath` | string | required | Path to logo/watermark image file | +| `--sizePct` | number | 0.2 | Size as percentage of base image width (0-1) | + +## Command Line Options + +### Common Options + +| Option | Type | Default | Description | +|--------|------|---------|-------------| +| `--src` | string | required | Source files (FILE\|FOLDER\|GLOB) | +| `--dst` | string | - | Destination path | +| `--watermarkType` | choice | required | "text" or "image" | +| `--position` | choice | "bottom-right" | Watermark position | +| `--margin` | number | 24 | Margin from edges in pixels | +| `--opacity` | number | 0.85 | Opacity level (0-1) | + +### Position Options + +- `top-left`: Upper left corner +- `top-right`: Upper right corner +- `bottom-left`: Lower left corner +- `bottom-right`: Lower right corner (default) +- `center`: Center of image + +### Utility Options + +| Option | Type | Default | Description | +|--------|------|---------|-------------| +| `--dry` | boolean | false | Preview mode (no files written) | +| `--verbose` | boolean | false | Show detailed processing info | +| `--debug` | boolean | false | Enable debug messages | +| `--logLevel` | string | "info" | Log level (warn\|info\|debug\|error) | + +## API Usage + +### Import the Library + +```typescript +import { + watermark, + addTextWatermark, + addLogoWatermark, + WatermarkOptions, + TextWatermarkOptions, + LogoWatermarkOptions +} from '@polymech/media'; +``` + +### Text Watermark API + +```typescript +import { addTextWatermark } from '@polymech/media'; + +await addTextWatermark( + 'input.jpg', + 'Ā© 2024 MyBrand', + 'output.jpg', + { + position: 'bottom-right', + fontSize: 48, + color: '#ffffff', + opacity: 0.9, + margin: 24, + fontFamily: 'Arial', + strokeColor: '#000000', + strokeWidth: 2 + } +); +``` + +### Image Watermark API + +```typescript +import { addLogoWatermark } from '@polymech/media'; + +await addLogoWatermark( + 'input.jpg', + 'logo.png', + 'output.jpg', + { + position: 'bottom-right', + sizePct: 0.2, + opacity: 0.85, + margin: 24, + blend: 'over' + } +); +``` + +### Batch Processing API + +```typescript +import { watermark } from '@polymech/media'; + +const options: WatermarkOptions = { + src: 'photos/*.jpg', + dst: 'output/', + watermarkType: 'text', + text: 'Ā© 2024 MyBrand', + textOptions: { + position: 'bottom-right', + fontSize: 48, + color: '#ffffff', + opacity: 0.9 + }, + // ... other IOptions +}; + +await watermark(options); +``` + +## Examples + +### Example 1: Brand Photos with Logo + +```bash +# Add company logo to product photos +pm-media watermark \ + --src "products/*.jpg" \ + --dst "branded/" \ + --watermarkType image \ + --logoPath "brand-logo.png" \ + --position bottom-right \ + --sizePct 0.12 \ + --opacity 0.8 \ + --margin 30 +``` + +### Example 2: Copyright Text on Multiple Formats + +```bash +# Add copyright to various image formats +pm-media watermark \ + --src "gallery/*.{jpg,png,webp}" \ + --dst "copyrighted/" \ + --watermarkType text \ + --text "Ā© 2024 Photography Studio" \ + --position bottom-left \ + --fontSize 28 \ + --color "#ffffff" \ + --strokeColor "#000000" \ + --strokeWidth 1 \ + --opacity 0.85 +``` + +### Example 3: Centered Watermark + +```bash +# Large central watermark for draft images +pm-media watermark \ + --src "drafts/*.jpg" \ + --dst "review/" \ + --watermarkType text \ + --text "DRAFT - NOT FOR PUBLICATION" \ + --position center \ + --fontSize 72 \ + --color "#ff0000" \ + --opacity 0.3 +``` + +### Example 4: Batch Processing with Dry Run + +```bash +# Preview changes before applying +pm-media watermark \ + --src "archive/**/*.jpg" \ + --dst "processed/" \ + --watermarkType image \ + --logoPath "watermark.png" \ + --dry \ + --verbose +``` + +### Example 5: Custom Logo Positioning + +```bash +# Small logo in top-right corner +pm-media watermark \ + --src "social-media/*.png" \ + --dst "branded/" \ + --watermarkType image \ + --logoPath "social-logo.png" \ + --position top-right \ + --sizePct 0.08 \ + --margin 15 \ + --opacity 0.9 +``` + +## File Format Support + +### Supported Input Formats +- JPEG (.jpg, .jpeg) +- PNG (.png) +- WebP (.webp) +- TIFF (.tiff, .tif) + +### Supported Output Formats +Output format is automatically determined by the destination file extension or input format. + +## Performance Tips + +1. **Batch Processing**: Process multiple files in one command for better performance +2. **Concurrency**: The tool processes files with controlled concurrency (default: 1) +3. **Logo Optimization**: Use PNG logos with transparency for best results +4. **Size Optimization**: Keep logo files reasonably sized to improve processing speed + +## Troubleshooting + +### Common Issues + +#### "Logo file not found" +```bash +# Ensure the logo path is correct and file exists +ls -la path/to/logo.png +``` + +#### "Unable to open for write" +```bash +# Ensure output directory exists +mkdir -p output/directory +``` + +#### Text appears blurry +- Increase `--fontSize` for better clarity +- Adjust `--strokeWidth` for better contrast +- Use appropriate `--color` contrast against background + +#### Logo appears too large/small +- Adjust `--sizePct` (0.1 = 10% of image width) +- Consider image dimensions when setting size + +### Debug Mode + +Enable detailed logging to troubleshoot issues: + +```bash +pm-media watermark \ + --src "input/*" \ + --dst "output/" \ + --watermarkType text \ + --text "Debug Test" \ + --debug \ + --verbose +``` + +### File Permissions + +Ensure you have: +- Read access to source files +- Write access to destination directory +- Execute permissions on the tool + +## Advanced Usage + +### Using Environment Variables + +```bash +export WATERMARK_TEXT="Ā© 2024 MyCompany" +export WATERMARK_LOGO="./assets/logo.png" + +pm-media watermark \ + --src "batch/*.jpg" \ + --dst "output/" \ + --watermarkType text \ + --text "$WATERMARK_TEXT" +``` + +### Integration with Scripts + +```bash +#!/bin/bash +# Automated watermarking script + +INPUT_DIR="$1" +OUTPUT_DIR="$2" +WATERMARK_TYPE="$3" + +if [ "$WATERMARK_TYPE" = "logo" ]; then + pm-media watermark \ + --src "$INPUT_DIR/*.jpg" \ + --dst "$OUTPUT_DIR/" \ + --watermarkType image \ + --logoPath "./branding/logo.png" \ + --position bottom-right +else + pm-media watermark \ + --src "$INPUT_DIR/*.jpg" \ + --dst "$OUTPUT_DIR/" \ + --watermarkType text \ + --text "Ā© $(date +%Y) MyBrand" \ + --position bottom-right +fi +``` + +## TypeScript Definitions + +```typescript +type Corner = "top-left" | "top-right" | "bottom-left" | "bottom-right" | "center"; + +interface LogoWatermarkOptions { + position?: Corner; + margin?: number; + sizePct?: number; + opacity?: number; + blend?: OverlayOptions["blend"]; +} + +interface TextWatermarkOptions { + position?: Corner; + margin?: number; + fontSize?: number; + opacity?: number; + color?: string; + fontFamily?: string; + strokeColor?: string; + strokeWidth?: number; +} + +interface WatermarkOptions extends IOptions { + watermarkType: 'text' | 'image'; + text?: string; + textOptions?: TextWatermarkOptions; + logoPath?: string; + imageOptions?: LogoWatermarkOptions; +} +``` + +## Contributing + +For bug reports, feature requests, or contributions, please visit the project repository. + +## License + +This tool is part of the @polymech/media package. Please refer to the package license for usage terms. diff --git a/packages/media/jpg_images/page_2.jpg b/packages/media/jpg_images/page_2.jpg deleted file mode 100644 index 778129f0..00000000 --- a/packages/media/jpg_images/page_2.jpg +++ /dev/null @@ -1 +0,0 @@ -mock-jpg-data \ No newline at end of file diff --git a/packages/media/jpg_images/page_3.jpg b/packages/media/jpg_images/page_3.jpg deleted file mode 100644 index 778129f0..00000000 --- a/packages/media/jpg_images/page_3.jpg +++ /dev/null @@ -1 +0,0 @@ -mock-jpg-data \ No newline at end of file diff --git a/packages/media/jpg_images/page_4.jpg b/packages/media/jpg_images/page_4.jpg deleted file mode 100644 index 778129f0..00000000 --- a/packages/media/jpg_images/page_4.jpg +++ /dev/null @@ -1 +0,0 @@ -mock-jpg-data \ No newline at end of file diff --git a/packages/media/log_test_1.png b/packages/media/log_test_1.png deleted file mode 100644 index 4a2adcec..00000000 --- a/packages/media/log_test_1.png +++ /dev/null @@ -1 +0,0 @@ -mock-png-data \ No newline at end of file diff --git a/packages/media/log_test_2.png b/packages/media/log_test_2.png deleted file mode 100644 index 4a2adcec..00000000 --- a/packages/media/log_test_2.png +++ /dev/null @@ -1 +0,0 @@ -mock-png-data \ No newline at end of file diff --git a/packages/media/log_test_3.png b/packages/media/log_test_3.png deleted file mode 100644 index 4a2adcec..00000000 --- a/packages/media/log_test_3.png +++ /dev/null @@ -1 +0,0 @@ -mock-png-data \ No newline at end of file diff --git a/packages/media/log_test_4.png b/packages/media/log_test_4.png deleted file mode 100644 index 4a2adcec..00000000 --- a/packages/media/log_test_4.png +++ /dev/null @@ -1 +0,0 @@ -mock-png-data \ No newline at end of file diff --git a/packages/media/log_test_5.png b/packages/media/log_test_5.png deleted file mode 100644 index 4a2adcec..00000000 --- a/packages/media/log_test_5.png +++ /dev/null @@ -1 +0,0 @@ -mock-png-data \ No newline at end of file diff --git a/packages/media/package-lock.json b/packages/media/package-lock.json index 38ac509c..53444c28 100644 --- a/packages/media/package-lock.json +++ b/packages/media/package-lock.json @@ -20,11 +20,11 @@ "fast-glob": "^3.3.2", "fluent-ffmpeg": "^2.1.3", "glob": "^11.0.0", - "glob-base": "^0.3.0", "js-beautify": "^1.14.6", "mupdf": "^1.3.3", "novita-sdk": "^1.0.37", "p-map": "^7.0.3", + "replicate": "^1.0.1", "sharp": "^0.34.2", "tslog": "^4.9.3", "typescript": "^5.8.3", @@ -32,7 +32,7 @@ "zod": "^3.25.74" }, "bin": { - "pm-media": "main.js" + "pm-media": "dist-in/main.js" }, "devDependencies": { "@types/glob": "^8.1.0", @@ -1691,6 +1691,19 @@ "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "license": "MIT", + "optional": true, + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, "node_modules/ansi-regex": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", @@ -1751,6 +1764,27 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "optional": true + }, "node_modules/bluebird": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", @@ -1768,6 +1802,31 @@ "node": ">=8" } }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "optional": true, + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, "node_modules/cac": { "version": "6.7.14", "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", @@ -2051,6 +2110,26 @@ "@types/estree": "^1.0.0" } }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.8.x" + } + }, "node_modules/expect-type": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.1.tgz", @@ -2237,49 +2316,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/glob-base": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", - "integrity": "sha512-ab1S1g1EbO7YzauaJLkgLp7DZVAqj9M/dvKlTt8DkXA2tiOIcSMrlVI2J1RZyB5iJVccEscjGn+kpOG9788MHA==", - "license": "MIT", - "dependencies": { - "glob-parent": "^2.0.0", - "is-glob": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/glob-base/node_modules/glob-parent": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", - "integrity": "sha512-JDYOvfxio/t42HKdxkAYaCiBN7oYiuxykOxKxdaUW5Qn0zaYN3gRQWolrwdnf0shM9/EP0ebuuTmyoXNr1cC5w==", - "license": "ISC", - "dependencies": { - "is-glob": "^2.0.0" - } - }, - "node_modules/glob-base/node_modules/is-extglob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha512-7Q+VbVafe6x2T+Tu6NcOf6sRklazEPmBoB3IWk3WdGZM2iGUwU/Oe3Wtq5lSEkDTTlpp8yx+5t4pzO/i9Ty1ww==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/glob-base/node_modules/is-glob": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", - "integrity": "sha512-a1dBeB19NXsf/E0+FHqkagizel/LQw2DjSQpvQrj3zT+jYPpaUCryPnrQajXKFLCMuf4I6FhRpaGtw4lPrG6Eg==", - "license": "MIT", - "dependencies": { - "is-extglob": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/glob-parent": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", @@ -2292,6 +2328,27 @@ "node": ">= 6" } }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause", + "optional": true + }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -2722,6 +2779,16 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 0.6.0" + } + }, "node_modules/proto-list": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", @@ -2757,6 +2824,38 @@ ], "license": "MIT" }, + "node_modules/readable-stream": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", + "license": "MIT", + "optional": true, + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/replicate": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/replicate/-/replicate-1.0.1.tgz", + "integrity": "sha512-EY+rK1YR5bKHcM9pd6WyaIbv6m2aRIvHfHDh51j/LahlHTLKemTYXF6ptif2sLa+YospupAsIoxw8Ndt5nI3vg==", + "license": "Apache-2.0", + "engines": { + "git": ">=2.11.0", + "node": ">=18.0.0", + "npm": ">=7.19.0", + "yarn": ">=1.7.0" + }, + "optionalDependencies": { + "readable-stream": ">=4.0.0" + } + }, "node_modules/reusify": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", @@ -2830,6 +2929,27 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "optional": true + }, "node_modules/semver": { "version": "5.7.2", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", @@ -2969,6 +3089,16 @@ "dev": true, "license": "MIT" }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "optional": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, "node_modules/string-width": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", @@ -4323,6 +4453,15 @@ "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" }, + "abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "optional": true, + "requires": { + "event-target-shim": "^5.0.0" + } + }, "ansi-regex": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", @@ -4364,6 +4503,12 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "optional": true + }, "bluebird": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", @@ -4377,6 +4522,16 @@ "fill-range": "^7.1.1" } }, + "buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "optional": true, + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, "cac": { "version": "6.7.14", "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", @@ -4586,6 +4741,18 @@ "@types/estree": "^1.0.0" } }, + "event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "optional": true + }, + "events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "optional": true + }, "expect-type": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.1.tgz", @@ -4695,38 +4862,6 @@ "path-scurry": "^2.0.0" } }, - "glob-base": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", - "integrity": "sha512-ab1S1g1EbO7YzauaJLkgLp7DZVAqj9M/dvKlTt8DkXA2tiOIcSMrlVI2J1RZyB5iJVccEscjGn+kpOG9788MHA==", - "requires": { - "glob-parent": "^2.0.0", - "is-glob": "^2.0.0" - }, - "dependencies": { - "glob-parent": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", - "integrity": "sha512-JDYOvfxio/t42HKdxkAYaCiBN7oYiuxykOxKxdaUW5Qn0zaYN3gRQWolrwdnf0shM9/EP0ebuuTmyoXNr1cC5w==", - "requires": { - "is-glob": "^2.0.0" - } - }, - "is-extglob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha512-7Q+VbVafe6x2T+Tu6NcOf6sRklazEPmBoB3IWk3WdGZM2iGUwU/Oe3Wtq5lSEkDTTlpp8yx+5t4pzO/i9Ty1ww==" - }, - "is-glob": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", - "integrity": "sha512-a1dBeB19NXsf/E0+FHqkagizel/LQw2DjSQpvQrj3zT+jYPpaUCryPnrQajXKFLCMuf4I6FhRpaGtw4lPrG6Eg==", - "requires": { - "is-extglob": "^1.0.0" - } - } - } - }, "glob-parent": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", @@ -4735,6 +4870,12 @@ "is-glob": "^4.0.1" } }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "optional": true + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -5020,6 +5161,12 @@ "source-map-js": "^1.2.1" } }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "optional": true + }, "proto-list": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", @@ -5040,6 +5187,27 @@ "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==" }, + "readable-stream": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", + "optional": true, + "requires": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + } + }, + "replicate": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/replicate/-/replicate-1.0.1.tgz", + "integrity": "sha512-EY+rK1YR5bKHcM9pd6WyaIbv6m2aRIvHfHDh51j/LahlHTLKemTYXF6ptif2sLa+YospupAsIoxw8Ndt5nI3vg==", + "requires": { + "readable-stream": ">=4.0.0" + } + }, "reusify": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", @@ -5083,6 +5251,12 @@ "queue-microtask": "^1.2.2" } }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "optional": true + }, "semver": { "version": "5.7.2", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", @@ -5181,6 +5355,15 @@ "integrity": "sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==", "dev": true }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "optional": true, + "requires": { + "safe-buffer": "~5.2.0" + } + }, "string-width": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", diff --git a/packages/media/package.json b/packages/media/package.json index a07dd91d..91e70766 100644 --- a/packages/media/package.json +++ b/packages/media/package.json @@ -6,7 +6,7 @@ "access": "public" }, "bin": { - "pm-media": "main.js" + "pm-media": "dist-in/main.js" }, "type": "module", "exports": { @@ -28,6 +28,7 @@ "mupdf": "^1.3.3", "novita-sdk": "^1.0.37", "p-map": "^7.0.3", + "replicate": "^1.0.1", "sharp": "^0.34.2", "tslog": "^4.9.3", "typescript": "^5.8.3", diff --git a/packages/media/src/commands/background-remove.ts b/packages/media/src/commands/background-remove.ts new file mode 100644 index 00000000..70cac64c --- /dev/null +++ b/packages/media/src/commands/background-remove.ts @@ -0,0 +1,102 @@ +import * as CLI from 'yargs' +import { CONFIG_DEFAULT } from '@polymech/commons' +import { logger } from '../index.js' +import { cli } from '../cli.js' +import { + sanitize, + defaults +} from '../_cli.js' + +import { + backgroundRemove, + BackgroundRemoveOptions +} from '../lib/media/images/background-remove.js' + +export const defaultOptions = (yargs: CLI.Argv) => { + return yargs.option('src', { + describe: 'FILE|FOLDER|GLOB', + demandOption: true + }).option('dst', { + describe: 'FILE|FOLDER|GLOB' + }).option('debug', { + default: false, + describe: 'Enable internal debug messages', + type: 'boolean' + }).option('alt', { + default: false, + describe: 'Use alternate tokenizer, & instead of $', + type: 'boolean' + }).option('dry', { + default: false, + describe: 'Run without conversion', + type: 'boolean' + }).option('verbose', { + default: false, + describe: 'Show internal messages', + type: 'boolean' + }).option('logLevel', { + describe: 'Log level : warn, info, debug, error', + type: 'string', + default: 'info' + }).option('apiKey', { + describe: 'Replicate API key (or set REPLICATE_API_TOKEN env var)', + type: 'string' + }).option('model', { + describe: 'Background removal model to use', + choices: ['u2net', 'u2netp', 'u2net_human_seg', 'u2net_cloth_seg', 'silueta'], + default: 'u2net' + }).option('alphaMattting', { + describe: 'Enable alpha matting for better edge refinement', + type: 'boolean', + default: false + }).option('alphaMattingForegroundThreshold', { + describe: 'Alpha matting foreground threshold', + type: 'number', + default: 270 + }).option('alphaMattingBackgroundThreshold', { + describe: 'Alpha matting background threshold', + type: 'number', + default: 10 + }).option('alphaMattingErodeSize', { + describe: 'Alpha matting erode size', + type: 'number', + default: 10 + }) +} + +export const command = 'background:remove'; +export const desc = 'Remove background from images using AI'; +export const builder = defaultOptions; + +export async function handler(argv: CLI.Arguments) { + defaults() + const options = sanitize(argv) as BackgroundRemoveOptions + logger.settings.minLevel = options.logLevel as any + const config: any = CONFIG_DEFAULT() + + // Get API key from argument or environment variable + options.apiKey = options.apiKey || process.env.REPLICATE_API_TOKEN || config?.replicate?.key; + + if (!options.apiKey) { + logger.error('Replicate API key is required. Provide it via --apiKey argument or set REPLICATE_API_TOKEN environment variable'); + logger.info('Get your API key at: https://replicate.com/account/api-tokens'); + process.exit(1); + } + + // Map CLI arguments to library options + options.model = argv.model as string; + options.alpha_matting = argv.alphaMattting as boolean; + options.alpha_matting_foreground_threshold = argv.alphaMattingForegroundThreshold as number; + options.alpha_matting_background_threshold = argv.alphaMattingBackgroundThreshold as number; + options.alpha_matting_erode_size = argv.alphaMattingErodeSize as number; + + logger.info("Removing background with options:", { + model: options.model, + alpha_matting: options.alpha_matting, + files: options.srcInfo?.FILES?.length || 0 + }); + + await backgroundRemove(options); +} + +cli.command(command, desc, builder, handler) diff --git a/packages/media/src/commands/resize.ts b/packages/media/src/commands/resize.ts index 15eb07f3..567231a2 100644 --- a/packages/media/src/commands/resize.ts +++ b/packages/media/src/commands/resize.ts @@ -64,14 +64,16 @@ export const defaultOptions = (yargs: CLI.Argv) => { }) } -let options = (yargs: CLI.Argv) => defaultOptions(yargs) +export const command = 'resize'; +export const desc = 'Resizes files'; +export const builder = defaultOptions; -export const register = (cli: CLI.Argv) => { - return cli.command('resize', 'Resizes files', options, async (argv: CLI.Arguments) => { - defaults() - const options = sanitize(argv) as IOptions - logger.settings.minLevel = options.logLevel as any - logger.info("options " + argv.dst, options) - await resize(options) - }) +export async function handler(argv: CLI.Arguments) { + defaults() + const options = sanitize(argv) as IOptions + logger.settings.minLevel = options.logLevel as any + logger.info("options " + argv.dst, options) + await resize(options) } + +cli.command(command, desc, builder, handler) diff --git a/packages/media/src/commands/watermark-rm.ts b/packages/media/src/commands/watermark-rm.ts new file mode 100644 index 00000000..8f7bfecd --- /dev/null +++ b/packages/media/src/commands/watermark-rm.ts @@ -0,0 +1,83 @@ +import { CONFIG_DEFAULT } from '@polymech/commons' +import * as CLI from 'yargs' +import { logger } from '../index.js' +import { + watermark +} from '../lib/media/images/watermark.js' + +import { + sanitize, + defaults +} from '../_cli.js' + +import { + IOptions +} from '../types.js' + +export const defaultOptions = (yargs: CLI.Argv) => { + return yargs.option('src', { + describe: 'FILE|FOLDER|GLOB', + demandOption: true + }).option('dst', { + describe: 'FILE|FOLDER|GLOB' + }).option('debug', { + default: false, + describe: 'Enable internal debug messages', + type: 'boolean' + }).option('alt', { + default: false, + describe: 'Use alternate tokenizer, & instead of $', + type: 'boolean' + }).option('dry', { + default: false, + describe: 'Run without conversion', + type: 'boolean' + }).option('verbose', { + default: false, + describe: 'Show internal messages', + type: 'boolean' + }).option('percent', { + default: false, + describe: 'Resize image with percent', + type: 'number' + }).option('width', { + default: false, + describe: 'Resize image with', + type: 'number' + }).option('height', { + default: false, + describe: 'Resize image height', + type: 'number' + }).option('minHeight', { + describe: 'Resize image minimum height', + type: 'number' + }).option('minWidth', { + describe: 'Resize image minimum width', + type: 'number' + }).option('minSize', { + describe: 'Resize image size (bytes)', + type: 'number' + }).option('percent', { + describe: 'Resize image in percent (width)', + type: 'number' + }).option('key', { + describe: 'API Key', + type: 'string' + }) +} + +const options = (yargs: CLI.Argv) => defaultOptions(yargs) + +export const register = (cli: CLI.Argv) => { + return cli.command('watermark', 'Remove watermark : FILE|GLOB', options, async (argv: CLI.Arguments) => { + defaults() + const options = sanitize(argv) as IOptions + const config: any = CONFIG_DEFAULT() + if (!config.novita) { + logger.error("Novita key not found"); + return + } + options.debug && logger.info("Watermark Options " + argv.dst, options) + return watermark({ ...options, key: config.novita.key }) + }) +} diff --git a/packages/media/src/commands/watermark.ts b/packages/media/src/commands/watermark.ts index 8f7bfecd..28b77647 100644 --- a/packages/media/src/commands/watermark.ts +++ b/packages/media/src/commands/watermark.ts @@ -1,83 +1,141 @@ -import { CONFIG_DEFAULT } from '@polymech/commons' import * as CLI from 'yargs' import { logger } from '../index.js' +import { cli } from '../cli.js' import { - watermark -} from '../lib/media/images/watermark.js' - -import { - sanitize, - defaults + sanitize, + defaults } from '../_cli.js' import { - IOptions + IOptions } from '../types.js' +import { + watermark, + WatermarkOptions +} from '../lib/media/images/watermark.js' + export const defaultOptions = (yargs: CLI.Argv) => { - return yargs.option('src', { - describe: 'FILE|FOLDER|GLOB', - demandOption: true - }).option('dst', { - describe: 'FILE|FOLDER|GLOB' - }).option('debug', { - default: false, - describe: 'Enable internal debug messages', - type: 'boolean' - }).option('alt', { - default: false, - describe: 'Use alternate tokenizer, & instead of $', - type: 'boolean' - }).option('dry', { - default: false, - describe: 'Run without conversion', - type: 'boolean' - }).option('verbose', { - default: false, - describe: 'Show internal messages', - type: 'boolean' - }).option('percent', { - default: false, - describe: 'Resize image with percent', - type: 'number' - }).option('width', { - default: false, - describe: 'Resize image with', - type: 'number' - }).option('height', { - default: false, - describe: 'Resize image height', - type: 'number' - }).option('minHeight', { - describe: 'Resize image minimum height', - type: 'number' - }).option('minWidth', { - describe: 'Resize image minimum width', - type: 'number' - }).option('minSize', { - describe: 'Resize image size (bytes)', - type: 'number' - }).option('percent', { - describe: 'Resize image in percent (width)', - type: 'number' - }).option('key', { - describe: 'API Key', - type: 'string' - }) + return yargs.option('src', { + describe: 'FILE|FOLDER|GLOB', + demandOption: true + }).option('dst', { + describe: 'FILE|FOLDER|GLOB' + }).option('debug', { + default: false, + describe: 'Enable internal debug messages', + type: 'boolean' + }).option('alt', { + default: false, + describe: 'Use alternate tokenizer, & instead of $', + type: 'boolean' + }).option('dry', { + default: false, + describe: 'Run without conversion', + type: 'boolean' + }).option('verbose', { + default: false, + describe: 'Show internal messages', + type: 'boolean' + }).option('logLevel', { + describe: 'Log level : warn, info, debug, error', + type: 'string', + default: 'info' + }).option('watermarkType', { + describe: 'Type of watermark: text or image', + choices: ['text', 'image'], + demandOption: true + }).option('text', { + describe: 'Text to use for text watermark', + type: 'string' + }).option('logoPath', { + describe: 'Path to logo image for image watermark', + type: 'string' + }).option('position', { + describe: 'Position of watermark', + choices: ['top-left', 'top-right', 'bottom-left', 'bottom-right', 'center'], + default: 'bottom-right' + }).option('margin', { + describe: 'Margin from edges in pixels', + type: 'number', + default: 24 + }).option('opacity', { + describe: 'Opacity of watermark (0-1)', + type: 'number', + default: 0.85 + }).option('sizePct', { + describe: 'Size of image watermark as percentage of base image width (0-1)', + type: 'number', + default: 0.2 + }).option('fontSize', { + describe: 'Font size for text watermark in pixels', + type: 'number', + default: 48 + }).option('color', { + describe: 'Text color (hex format, e.g., #ffffff)', + type: 'string', + default: '#ffffff' + }).option('fontFamily', { + describe: 'Font family for text watermark', + type: 'string', + default: 'Arial' + }).option('strokeColor', { + describe: 'Text stroke color (hex format, e.g., #000000)', + type: 'string', + default: '#000000' + }).option('strokeWidth', { + describe: 'Text stroke width in pixels', + type: 'number', + default: 2 + }) } -const options = (yargs: CLI.Argv) => defaultOptions(yargs) -export const register = (cli: CLI.Argv) => { - return cli.command('watermark', 'Remove watermark : FILE|GLOB', options, async (argv: CLI.Arguments) => { + +export const command = 'watermark'; +export const desc = 'Adds watermarks to images'; +export const builder = defaultOptions; + +export async function handler(argv: CLI.Arguments) { defaults() - const options = sanitize(argv) as IOptions - const config: any = CONFIG_DEFAULT() - if (!config.novita) { - logger.error("Novita key not found"); - return + const options = sanitize(argv) as WatermarkOptions + logger.settings.minLevel = options.logLevel as any + + // Validate required options based on watermark type + if (options.watermarkType === 'text' && !options.text) { + logger.error('Text is required when using text watermark type') + process.exit(1) } - options.debug && logger.info("Watermark Options " + argv.dst, options) - return watermark({ ...options, key: config.novita.key }) - }) + + if (options.watermarkType === 'image' && !options.logoPath) { + logger.error('Logo path is required when using image watermark type') + process.exit(1) + } + + // Set up watermark options based on type + if (options.watermarkType === 'text') { + options.textOptions = { + position: argv.position as any, + margin: argv.margin as number, + fontSize: argv.fontSize as number, + opacity: argv.opacity as number, + color: argv.color as string, + fontFamily: argv.fontFamily as string, + strokeColor: argv.strokeColor as string, + strokeWidth: argv.strokeWidth as number, + } + } else if (options.watermarkType === 'image') { + options.imageOptions = { + position: argv.position as any, + margin: argv.margin as number, + sizePct: argv.sizePct as number, + opacity: argv.opacity as number, + blend: 'over' + } + } + + logger.info("Adding watermark with options:", options) + await watermark(options) } + +cli.command(command, desc, builder, handler) \ No newline at end of file diff --git a/packages/media/src/lib/media/images/background-remove.ts b/packages/media/src/lib/media/images/background-remove.ts new file mode 100644 index 00000000..3ccfedc3 --- /dev/null +++ b/packages/media/src/lib/media/images/background-remove.ts @@ -0,0 +1,146 @@ +import * as fs from 'fs'; +import * as path from 'path'; +import pMap from 'p-map'; +import { logger } from '../../../index.js'; +import { IOptions } from '../../../types.js'; +import { targets } from '../../index.js'; +import { sync as mkdir } from '@polymech/fs/dir'; + +// https://replicate.com/cjwbw/rembg +export interface BackgroundRemoveOptions extends IOptions { + apiKey?: string; + model?: string; + alpha_matting?: boolean; + alpha_matting_foreground_threshold?: number; + alpha_matting_background_threshold?: number; + alpha_matting_erode_size?: number; +} + +// Base64 encode image file +function encodeImageToBase64(filePath: string): string { + const imageBuffer = fs.readFileSync(filePath); + return `data:image/${path.extname(filePath).slice(1)};base64,${imageBuffer.toString('base64')}`; +} + +// Save FileOutput from Replicate API to file +async function saveReplicateOutput(output: any, outputPath: string): Promise { + // Ensure output directory exists + mkdir(path.dirname(outputPath)); + + // Handle FileOutput from Replicate API + if (output && typeof output.url === 'function') { + // This is a FileOutput object from Replicate + logger.debug(`Saving FileOutput to: ${outputPath}`); + await fs.promises.writeFile(outputPath, output); + } else if (typeof output === 'string' && output.startsWith('http')) { + // This is a URL, fetch and save the image + logger.debug(`Downloading image from URL: ${output}`); + const response = await fetch(output); + const arrayBuffer = await response.arrayBuffer(); + const buffer = Buffer.from(arrayBuffer); + fs.writeFileSync(outputPath, buffer); + } else if (typeof output === 'string') { + // This might be base64 data + let base64String = output.replace(/^data:image\/[a-z]+;base64,/, ''); + const imageBuffer = Buffer.from(base64String, 'base64'); + fs.writeFileSync(outputPath, imageBuffer); + } else if (Buffer.isBuffer(output)) { + // Already a buffer + fs.writeFileSync(outputPath, output); + } else { + throw new Error(`Unexpected output format: ${typeof output}, ${JSON.stringify(output).substring(0, 200)}`); + } +} + +export async function removeBackgroundFile( + inputPath: string, + outputPath: string, + options: BackgroundRemoveOptions +): Promise { + try { + if (!options.apiKey) { + throw new Error('Replicate API key is required. Set it via --apiKey or REPLICATE_API_TOKEN environment variable'); + } + + // Import Replicate dynamically to handle potential installation issues + let Replicate; + try { + const replicateModule = await import('replicate'); + Replicate = replicateModule.default; + } catch (error) { + throw new Error('Replicate package not found. Please install it with: npm install replicate'); + } + + const replicate = new Replicate({ + auth: options.apiKey, + }); + + logger.debug(`Removing background from ${inputPath}`); + + // Encode input image to base64 data URL + const inputImageBase64 = encodeImageToBase64(inputPath); + + // Prepare input for the model + const input = { + image: inputImageBase64, + model: options.model || 'u2net', + alpha_matting: options.alpha_matting || false, + alpha_matting_foreground_threshold: options.alpha_matting_foreground_threshold || 270, + alpha_matting_background_threshold: options.alpha_matting_background_threshold || 10, + alpha_matting_erode_size: options.alpha_matting_erode_size || 10, + }; + + // Run the background removal model + const output = await replicate.run("cjwbw/rembg:fb8af171cfa1616ddcf1242c093f9c46bcada5ad4cf6f2fbe8b81b330ec5c003", { + input + }); + + logger.debug(`API response type: ${typeof output}`); + logger.debug(`API response has url method: ${typeof output?.url}`); + + if (output && typeof output.url === 'function') { + logger.debug(`Output URL: ${output.url()}`); + } + + // Save the result + await saveReplicateOutput(output, outputPath); + + logger.info(`Background removed: ${inputPath} → ${outputPath}`); + } catch (error) { + logger.error(`Failed to remove background from ${inputPath}:`, error.message); + throw error; + } +} + +const _backgroundRemove = async ( + file: string, + targets: string[], + onNode: (data: any) => void = () => {}, + options: BackgroundRemoveOptions +) => { + return pMap(targets, async (target) => { + options.verbose && logger.debug(`Removing background ${file} to ${target}`); + if (options.dry) { + logger.info(`[DRY RUN] Would remove background: ${file} → ${target}`); + return; + } + return await removeBackgroundFile(file, target, options); + }, { concurrency: 1 }); +}; + +export const backgroundRemove = async (options: BackgroundRemoveOptions) => { + // reporting, stub + let reports: any = []; + const onNode = (data: any) => reports.push(data); + + if (options.srcInfo) { + options.verbose && logger.info(`Removing background from ${options.srcInfo.FILES.length} files`); + return await pMap(options.srcInfo.FILES, async (f) => { + const outputs = targets(f, options); + options.verbose && logger.info(`Removing background ${f} to`, outputs); + return _backgroundRemove(f, outputs, onNode, options); + }, { concurrency: 1 }); + } else { + options.debug && logger.error(`Invalid source info`); + } +}; diff --git a/packages/media/src/lib/media/images/watermark.ts b/packages/media/src/lib/media/images/watermark.ts index 6c90fd35..af951f1a 100644 --- a/packages/media/src/lib/media/images/watermark.ts +++ b/packages/media/src/lib/media/images/watermark.ts @@ -1,65 +1,247 @@ -// https://novita.ai/playground#remove-watermark -import * as fs from 'fs' -import * as path from 'path' -import { CONFIG_DEFAULT } from '@polymech/commons' -import BPromise from 'bluebird' -import { async as write } from "@polymech/fs/write" -import { - logger -} from '../../../index.js' +import sharp, { OverlayOptions } from "sharp"; +import * as path from 'path'; +import * as fs from 'fs'; +import { glob } from 'glob'; +import pMap from 'p-map'; +import { logger } from '../../../index.js'; +import { IOptions } from '../../../types.js'; +import { targets } from '../../index.js'; +import { sync as mkdir } from '@polymech/fs/dir' -import { - IOptions, - IResizeOptions -} from '../../../types.js' +type Corner = "top-left" | "top-right" | "bottom-left" | "bottom-right" | "center"; -import { - imageToBase64, - base64ToBuffer -} from './lib.js' +export interface LogoWatermarkOptions { + position?: Corner; + margin?: number; // px + sizePct?: number; // of base image width (0–1) + opacity?: number; // 0–1 + blend?: OverlayOptions["blend"]; +} +export interface TextWatermarkOptions { + position?: Corner; + margin?: number; // px + fontSize?: number; // px + opacity?: number; // 0–1 + color?: string; // hex color like '#ffffff' + fontFamily?: string; // font family + strokeColor?: string; // outline color + strokeWidth?: number; // outline width +} -import { NovitaSDK } from "novita-sdk" -import { targets, targetsNext } from '../../index.js' +export interface WatermarkOptions extends IOptions { + // Watermark type + watermarkType: 'text' | 'image'; + + // Text watermark options + text?: string; + textOptions?: TextWatermarkOptions; + + // Image watermark options + logoPath?: string; + imageOptions?: LogoWatermarkOptions; +} -const removeWatermark = async (file, target, onNode: (data: any) => void = () => { }, options: IResizeOptions) => { - const novitaClient = new NovitaSDK(options.key) - const params = { - image_file: await imageToBase64(file) - //"data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD", - } - try { - const wMark = await novitaClient.removeWatermark(params) - logger.info(`Watermark removed: ${file} to ${target}`) - write(target,base64ToBuffer(wMark.image_file)) - } catch (error) { - logger.error(`Failed to remove watermark: ${error.msg}`) +export async function addLogoWatermark( + inputPath: string, + logoPath: string, + outputPath: string, + opts: LogoWatermarkOptions = {} +): Promise { + const { + position = "bottom-right", + margin = 24, + sizePct = 0.2, + opacity = 0.85, + blend = "over", + } = opts; + + const base = sharp(inputPath); + const { width: W = 0, height: H = 0 } = await base.metadata(); + if (!W || !H) throw new Error("Could not read base image size"); + + // Resize logo to sizePct of base width + const logoWidth = Math.max(1, Math.round(W * sizePct)); + const logoBuf = await sharp(logoPath).resize({ width: logoWidth }).toBuffer(); + const { width: w = 0, height: h = 0 } = await sharp(logoBuf).metadata(); + + // Compute pixel placement + const pos = (() => { + switch (position) { + case "top-left": return { left: margin, top: margin }; + case "top-right": return { left: W - w - margin, top: margin }; + case "bottom-left": return { left: margin, top: H - h - margin }; + case "center": return { left: Math.round((W - w) / 2), top: Math.round((H - h) / 2) }; + case "bottom-right": + default: return { left: W - w - margin, top: H - h - margin }; } + })(); + + // Ensure output directory exists + mkdir(path.dirname(outputPath)); + + await base + .composite([{ + input: logoBuf, + left: pos.left, + top: pos.top, + blend, + ...(opacity < 1 ? { blend: 'multiply' } : {}), + }]) + .toFile(outputPath); } -const _watermark = async (file, targets: string[], onNode: (data: any) => void = () => { }, options: IOptions) => { - return BPromise.resolve(targets).map((target) => { - options.verbose && logger.debug(`Removing Watermark ${file} to ${target}`) - if (options.dry) { - return BPromise.resolve() - } - return removeWatermark(file, target, onNode, options); - }, { concurrency: 1 }) +export async function addTextWatermark( + inputPath: string, + text: string, + outputPath: string, + opts: TextWatermarkOptions = {} +): Promise { + const { + position = "bottom-right", + margin = 24, + fontSize = 48, + opacity = 0.8, + color = '#ffffff', + fontFamily = 'Arial', + strokeColor = '#000000', + strokeWidth = 2, + } = opts; + + const base = sharp(inputPath); + const { width: W = 0, height: H = 0 } = await base.metadata(); + if (!W || !H) throw new Error("Could not read base image size"); + + // Create SVG text element + const svgText = ` + + + ${text} + + + `; + + const textBuffer = Buffer.from(svgText); + + // Ensure output directory exists + mkdir(path.dirname(outputPath)); + + await base + .composite([{ + input: textBuffer, + left: 0, + top: 0, + blend: 'over', + }]) + .toFile(outputPath); } -export const watermark = async (options: IOptions) => { - - // reporting, stub - let reports: any = [] - const onNode = (data: any) => reports.push(data) - if (options.srcInfo) { - options.verbose && logger.info(`Convert ${options.srcInfo.FILES.length} files`) - return await BPromise.resolve(options.srcInfo.FILES).map((f) => { - const outputs = targets(f, options) - options.verbose && logger.info(`Convert ${f} to `, outputs) - return _watermark(f, outputs, onNode, options) - }, { concurrency: 1 }) +function getTextX(position: Corner, width: number, margin: number): number { + switch (position) { + case "top-left": + case "bottom-left": + return margin; + case "top-right": + case "bottom-right": + return width - margin; + case "center": + default: + return width / 2; + } +} + +function getTextY(position: Corner, height: number, margin: number, fontSize: number): number { + switch (position) { + case "top-left": + case "top-right": + return margin + fontSize; + case "bottom-left": + case "bottom-right": + return height - margin; + case "center": + default: + return height / 2; + } +} + +function getTextAnchor(position: Corner): string { + switch (position) { + case "top-left": + case "bottom-left": + return "start"; + case "top-right": + case "bottom-right": + return "end"; + case "center": + default: + return "middle"; + } +} + +function getTextBaseline(position: Corner): string { + switch (position) { + case "top-left": + case "top-right": + return "hanging"; + case "bottom-left": + case "bottom-right": + return "auto"; + case "center": + default: + return "middle"; + } +} + +const _watermark = async (file: string, targets: string[], onNode: (data: any) => void = () => { }, options: WatermarkOptions) => { + return pMap(targets, async (target) => { + options.verbose && logger.debug(`Adding watermark ${file} to ${target}`); + if (options.dry) { + return; + } + + if (options.watermarkType === 'text') { + if (!options.text) { + throw new Error('Text is required for text watermark'); + } + return addTextWatermark(file, options.text, target, options.textOptions); + } else if (options.watermarkType === 'image') { + if (!options.logoPath) { + throw new Error('Logo path is required for image watermark'); + } + if (!fs.existsSync(options.logoPath)) { + throw new Error(`Logo file not found: ${options.logoPath}`); + } + return addLogoWatermark(file, options.logoPath, target, options.imageOptions); } else { - options.debug && logger.error(`Invalid source info`) + throw new Error('Invalid watermark type. Must be "text" or "image"'); } -} + }, { concurrency: 1 }); +}; + +export const watermark = async (options: WatermarkOptions) => { + // reporting, stub + let reports: any = []; + const onNode = (data: any) => reports.push(data); + + if (options.srcInfo) { + options.verbose && logger.info(`Adding watermark to ${options.srcInfo.FILES.length} files`); + return await pMap(options.srcInfo.FILES, async (f) => { + const outputs = targets(f, options); + options.verbose && logger.info(`Adding watermark ${f} to `, outputs); + return _watermark(f, outputs, onNode, options); + }, { concurrency: 1 }); + } else { + options.debug && logger.error(`Invalid source info`); + } +}; \ No newline at end of file diff --git a/packages/media/src/main.ts b/packages/media/src/main.ts index c428951e..a71fe743 100644 --- a/packages/media/src/main.ts +++ b/packages/media/src/main.ts @@ -2,8 +2,11 @@ import { defaults } from './_cli.js'; defaults() import { cli } from './cli.js' + import './commands/resize.js' import './commands/pdf2jpg.js' +import './commands/watermark.js' +import './commands/background-remove.js' const argv: any = cli.argv; diff --git a/packages/media/src/types.ts b/packages/media/src/types.ts index 4a5276a2..581f6828 100644 --- a/packages/media/src/types.ts +++ b/packages/media/src/types.ts @@ -54,4 +54,10 @@ export type IConvertVideoOptions = IOptions & { interval?: number verb: string audio: string -} \ No newline at end of file +} + +// Re-export watermark types from the watermark module +export type { WatermarkOptions, LogoWatermarkOptions, TextWatermarkOptions } from './lib/media/images/watermark.js' + +// Re-export background removal types +export type { BackgroundRemoveOptions } from './lib/media/images/background-remove.js' \ No newline at end of file diff --git a/packages/media/tests/images/watermark-add/DSC05572.JPG b/packages/media/tests/images/watermark-add/DSC05572.JPG new file mode 100644 index 00000000..003848a3 Binary files /dev/null and b/packages/media/tests/images/watermark-add/DSC05572.JPG differ diff --git a/packages/media/tests/images/watermark-add/DSC05575.JPG b/packages/media/tests/images/watermark-add/DSC05575.JPG new file mode 100644 index 00000000..16b073f5 Binary files /dev/null and b/packages/media/tests/images/watermark-add/DSC05575.JPG differ diff --git a/packages/media/tests/images/watermark-add/DSC05620.JPG b/packages/media/tests/images/watermark-add/DSC05620.JPG new file mode 100644 index 00000000..2299125f Binary files /dev/null and b/packages/media/tests/images/watermark-add/DSC05620.JPG differ diff --git a/packages/media/tests/images/watermark-add/DSC05627.JPG b/packages/media/tests/images/watermark-add/DSC05627.JPG new file mode 100644 index 00000000..0845f4e0 Binary files /dev/null and b/packages/media/tests/images/watermark-add/DSC05627.JPG differ diff --git a/packages/media/tests/images/watermark-add/DSC05630.JPG b/packages/media/tests/images/watermark-add/DSC05630.JPG new file mode 100644 index 00000000..9ff0ad5c Binary files /dev/null and b/packages/media/tests/images/watermark-add/DSC05630.JPG differ diff --git a/packages/media/tests/images/watermark-add/DSC05633.JPG b/packages/media/tests/images/watermark-add/DSC05633.JPG new file mode 100644 index 00000000..27759433 Binary files /dev/null and b/packages/media/tests/images/watermark-add/DSC05633.JPG differ diff --git a/packages/media/tests/images/watermark-add/DSC05634.JPG b/packages/media/tests/images/watermark-add/DSC05634.JPG new file mode 100644 index 00000000..426641ad Binary files /dev/null and b/packages/media/tests/images/watermark-add/DSC05634.JPG differ diff --git a/packages/media/tests/images/watermark-add/DSC05639.JPG b/packages/media/tests/images/watermark-add/DSC05639.JPG new file mode 100644 index 00000000..3d888776 Binary files /dev/null and b/packages/media/tests/images/watermark-add/DSC05639.JPG differ diff --git a/packages/media/tests/images/watermark-add/DSC05640.JPG b/packages/media/tests/images/watermark-add/DSC05640.JPG new file mode 100644 index 00000000..aa1c7987 Binary files /dev/null and b/packages/media/tests/images/watermark-add/DSC05640.JPG differ diff --git a/packages/media/tests/images/watermark-out/DSC05572.JPG b/packages/media/tests/images/watermark-out/DSC05572.JPG new file mode 100644 index 00000000..cb597ebd Binary files /dev/null and b/packages/media/tests/images/watermark-out/DSC05572.JPG differ diff --git a/packages/media/tests/images/watermark-out/DSC05575.JPG b/packages/media/tests/images/watermark-out/DSC05575.JPG new file mode 100644 index 00000000..eb7eab2c Binary files /dev/null and b/packages/media/tests/images/watermark-out/DSC05575.JPG differ diff --git a/packages/media/tests/images/watermark-out/DSC05620.JPG b/packages/media/tests/images/watermark-out/DSC05620.JPG new file mode 100644 index 00000000..3b77939d Binary files /dev/null and b/packages/media/tests/images/watermark-out/DSC05620.JPG differ diff --git a/packages/media/tests/images/watermark-out/DSC05627.JPG b/packages/media/tests/images/watermark-out/DSC05627.JPG new file mode 100644 index 00000000..a2b45be9 Binary files /dev/null and b/packages/media/tests/images/watermark-out/DSC05627.JPG differ diff --git a/packages/media/tests/images/watermark-out/DSC05630.JPG b/packages/media/tests/images/watermark-out/DSC05630.JPG new file mode 100644 index 00000000..abffa689 Binary files /dev/null and b/packages/media/tests/images/watermark-out/DSC05630.JPG differ diff --git a/packages/media/tests/images/watermark-out/DSC05633.JPG b/packages/media/tests/images/watermark-out/DSC05633.JPG new file mode 100644 index 00000000..94c0d2f2 Binary files /dev/null and b/packages/media/tests/images/watermark-out/DSC05633.JPG differ diff --git a/packages/media/tests/images/watermark-out/DSC05634.JPG b/packages/media/tests/images/watermark-out/DSC05634.JPG new file mode 100644 index 00000000..d2db6356 Binary files /dev/null and b/packages/media/tests/images/watermark-out/DSC05634.JPG differ diff --git a/packages/media/tests/images/watermark-out/DSC05639.JPG b/packages/media/tests/images/watermark-out/DSC05639.JPG new file mode 100644 index 00000000..c61c6f36 Binary files /dev/null and b/packages/media/tests/images/watermark-out/DSC05639.JPG differ diff --git a/packages/media/tests/images/watermark-out/DSC05640.JPG b/packages/media/tests/images/watermark-out/DSC05640.JPG new file mode 100644 index 00000000..40055d01 Binary files /dev/null and b/packages/media/tests/images/watermark-out/DSC05640.JPG differ diff --git a/packages/media/tests/images/watermark-rm-out/DSC05572.JPG b/packages/media/tests/images/watermark-rm-out/DSC05572.JPG new file mode 100644 index 00000000..b6cf1faf Binary files /dev/null and b/packages/media/tests/images/watermark-rm-out/DSC05572.JPG differ diff --git a/packages/media/tests/images/watermark-rm-out/DSC05575.JPG b/packages/media/tests/images/watermark-rm-out/DSC05575.JPG new file mode 100644 index 00000000..48769f5f Binary files /dev/null and b/packages/media/tests/images/watermark-rm-out/DSC05575.JPG differ diff --git a/packages/media/tests/images/watermark-rm-out/DSC05620.JPG b/packages/media/tests/images/watermark-rm-out/DSC05620.JPG new file mode 100644 index 00000000..59e0dba8 Binary files /dev/null and b/packages/media/tests/images/watermark-rm-out/DSC05620.JPG differ diff --git a/packages/media/tests/images/watermark-rm-out/DSC05627.JPG b/packages/media/tests/images/watermark-rm-out/DSC05627.JPG new file mode 100644 index 00000000..0791de70 Binary files /dev/null and b/packages/media/tests/images/watermark-rm-out/DSC05627.JPG differ diff --git a/packages/media/tests/images/watermark-rm-out/DSC05630.JPG b/packages/media/tests/images/watermark-rm-out/DSC05630.JPG new file mode 100644 index 00000000..a13982fe Binary files /dev/null and b/packages/media/tests/images/watermark-rm-out/DSC05630.JPG differ diff --git a/packages/media/tests/images/watermark-rm-out/DSC05633.JPG b/packages/media/tests/images/watermark-rm-out/DSC05633.JPG new file mode 100644 index 00000000..073e5aef Binary files /dev/null and b/packages/media/tests/images/watermark-rm-out/DSC05633.JPG differ diff --git a/packages/media/tests/images/watermark-rm-out/DSC05634.JPG b/packages/media/tests/images/watermark-rm-out/DSC05634.JPG new file mode 100644 index 00000000..cf54b670 Binary files /dev/null and b/packages/media/tests/images/watermark-rm-out/DSC05634.JPG differ diff --git a/packages/media/tests/images/watermark-rm-out/DSC05639.JPG b/packages/media/tests/images/watermark-rm-out/DSC05639.JPG new file mode 100644 index 00000000..d1169417 Binary files /dev/null and b/packages/media/tests/images/watermark-rm-out/DSC05639.JPG differ diff --git a/packages/media/tests/images/watermark-rm-out/DSC05640.JPG b/packages/media/tests/images/watermark-rm-out/DSC05640.JPG new file mode 100644 index 00000000..98f911d0 Binary files /dev/null and b/packages/media/tests/images/watermark-rm-out/DSC05640.JPG differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact.pdf b/packages/media/tests/pdf/MS300-Manual-Compact.pdf new file mode 100644 index 00000000..08b58c32 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact.pdf differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_188.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_188.png new file mode 100644 index 00000000..79c4cd91 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_188.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_189.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_189.png new file mode 100644 index 00000000..55a94733 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_189.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_190.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_190.png new file mode 100644 index 00000000..5c16744b Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_190.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_191.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_191.png new file mode 100644 index 00000000..b549fe35 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_191.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_192.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_192.png new file mode 100644 index 00000000..26cc87c1 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_192.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_193.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_193.png new file mode 100644 index 00000000..87ad6439 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_193.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_194.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_194.png new file mode 100644 index 00000000..89d28ac4 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_194.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_195.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_195.png new file mode 100644 index 00000000..e5a0f225 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_195.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_196.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_196.png new file mode 100644 index 00000000..9efd7a8f Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_196.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_197.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_197.png new file mode 100644 index 00000000..be678341 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_197.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_198.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_198.png new file mode 100644 index 00000000..a6f76155 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_198.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_199.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_199.png new file mode 100644 index 00000000..121c4118 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_199.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_200.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_200.png new file mode 100644 index 00000000..7664dd89 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_200.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_201.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_201.png new file mode 100644 index 00000000..56eff0a1 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_201.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_202.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_202.png new file mode 100644 index 00000000..6393f097 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_202.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_203.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_203.png new file mode 100644 index 00000000..ee7603fe Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_203.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_204.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_204.png new file mode 100644 index 00000000..29bd9483 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_204.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_205.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_205.png new file mode 100644 index 00000000..456afe81 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_205.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_206.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_206.png new file mode 100644 index 00000000..91ee0329 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_206.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_207.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_207.png new file mode 100644 index 00000000..b0a75b30 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_207.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_208.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_208.png new file mode 100644 index 00000000..ca2d2231 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_208.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_209.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_209.png new file mode 100644 index 00000000..d419a18d Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_209.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_210.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_210.png new file mode 100644 index 00000000..31839f61 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_210.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_211.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_211.png new file mode 100644 index 00000000..769c1966 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_211.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_212.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_212.png new file mode 100644 index 00000000..3388e759 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_212.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_213.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_213.png new file mode 100644 index 00000000..c20d3104 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_213.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_214.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_214.png new file mode 100644 index 00000000..08fca6f0 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_214.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_215.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_215.png new file mode 100644 index 00000000..36ced91b Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_215.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_216.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_216.png new file mode 100644 index 00000000..8ba63479 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_216.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_217.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_217.png new file mode 100644 index 00000000..67738804 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_217.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_218.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_218.png new file mode 100644 index 00000000..2c4d8562 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_218.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_219.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_219.png new file mode 100644 index 00000000..89c8cdb0 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_219.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_220.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_220.png new file mode 100644 index 00000000..ada7e841 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_220.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_221.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_221.png new file mode 100644 index 00000000..10e70ece Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_221.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_222.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_222.png new file mode 100644 index 00000000..71e070dc Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_222.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_223.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_223.png new file mode 100644 index 00000000..177191a4 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_223.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_224.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_224.png new file mode 100644 index 00000000..dcdad9cb Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_224.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_225.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_225.png new file mode 100644 index 00000000..9310c923 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_225.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_226.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_226.png new file mode 100644 index 00000000..37ee77b8 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_226.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_227.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_227.png new file mode 100644 index 00000000..1dd5d44d Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_227.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_228.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_228.png new file mode 100644 index 00000000..33c11da4 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_228.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_229.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_229.png new file mode 100644 index 00000000..72c0e79d Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_229.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_230.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_230.png new file mode 100644 index 00000000..239b96ac Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_230.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_231.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_231.png new file mode 100644 index 00000000..a57eb75d Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_231.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_232.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_232.png new file mode 100644 index 00000000..7670947d Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_232.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_233.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_233.png new file mode 100644 index 00000000..f977dbb9 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_233.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_234.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_234.png new file mode 100644 index 00000000..7c4f48d2 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_234.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_235.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_235.png new file mode 100644 index 00000000..e84f0e2f Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_235.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_236.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_236.png new file mode 100644 index 00000000..201e7b83 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_236.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_237.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_237.png new file mode 100644 index 00000000..0ef013d8 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_237.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_238.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_238.png new file mode 100644 index 00000000..a36b0060 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_238.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_239.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_239.png new file mode 100644 index 00000000..f1dceade Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_239.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_240.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_240.png new file mode 100644 index 00000000..cbe8e95e Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_240.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_241.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_241.png new file mode 100644 index 00000000..ea450fa3 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_241.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_242.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_242.png new file mode 100644 index 00000000..c1acd2a7 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_242.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_243.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_243.png new file mode 100644 index 00000000..9e0950e3 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_243.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_244.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_244.png new file mode 100644 index 00000000..c2376026 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_244.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_245.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_245.png new file mode 100644 index 00000000..39dbe7d8 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_245.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_246.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_246.png new file mode 100644 index 00000000..f481673a Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_246.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_247.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_247.png new file mode 100644 index 00000000..8115fc12 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_247.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_248.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_248.png new file mode 100644 index 00000000..41eea32e Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_248.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_249.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_249.png new file mode 100644 index 00000000..551e6f82 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_249.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_250.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_250.png new file mode 100644 index 00000000..7b3dc960 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_250.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_251.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_251.png new file mode 100644 index 00000000..332ccf2c Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_251.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_252.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_252.png new file mode 100644 index 00000000..a30d1b64 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_252.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_253.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_253.png new file mode 100644 index 00000000..7dd60b08 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_253.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_254.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_254.png new file mode 100644 index 00000000..f32be340 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_254.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_255.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_255.png new file mode 100644 index 00000000..b89c0f6e Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_255.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_256.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_256.png new file mode 100644 index 00000000..84a3cb4b Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_256.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_257.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_257.png new file mode 100644 index 00000000..7fd88d76 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_257.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_258.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_258.png new file mode 100644 index 00000000..3f855c44 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_258.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_259.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_259.png new file mode 100644 index 00000000..6449eb2d Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_259.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_260.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_260.png new file mode 100644 index 00000000..6a60d14d Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_260.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_261.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_261.png new file mode 100644 index 00000000..fb781017 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_261.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_262.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_262.png new file mode 100644 index 00000000..edd8becd Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_262.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_263.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_263.png new file mode 100644 index 00000000..27c6d582 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_263.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_264.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_264.png new file mode 100644 index 00000000..eb2a2007 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_264.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_265.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_265.png new file mode 100644 index 00000000..2f585e33 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_265.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_266.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_266.png new file mode 100644 index 00000000..aa51e91d Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_266.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_267.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_267.png new file mode 100644 index 00000000..7a1a8ed3 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_267.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_268.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_268.png new file mode 100644 index 00000000..8ec78830 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_268.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_269.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_269.png new file mode 100644 index 00000000..88e9205b Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_269.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_270.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_270.png new file mode 100644 index 00000000..371cda8b Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_270.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_271.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_271.png new file mode 100644 index 00000000..90e9af4e Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_271.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_272.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_272.png new file mode 100644 index 00000000..d276cbaa Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_272.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_273.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_273.png new file mode 100644 index 00000000..a6ffeb0f Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_273.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_274.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_274.png new file mode 100644 index 00000000..812a49ee Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_274.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_275.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_275.png new file mode 100644 index 00000000..25a359a8 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_275.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_276.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_276.png new file mode 100644 index 00000000..d96385b9 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_276.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_277.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_277.png new file mode 100644 index 00000000..daf47f34 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_277.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_278.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_278.png new file mode 100644 index 00000000..b3c81210 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_278.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_279.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_279.png new file mode 100644 index 00000000..4a617ab0 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_279.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_280.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_280.png new file mode 100644 index 00000000..0efe283b Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_280.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_281.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_281.png new file mode 100644 index 00000000..b6877192 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_281.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_282.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_282.png new file mode 100644 index 00000000..b514041c Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_282.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_283.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_283.png new file mode 100644 index 00000000..18070184 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_283.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_284.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_284.png new file mode 100644 index 00000000..885755dc Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_284.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_285.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_285.png new file mode 100644 index 00000000..17449826 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_285.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_286.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_286.png new file mode 100644 index 00000000..657b33c0 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_286.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_287.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_287.png new file mode 100644 index 00000000..7c84677a Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_287.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_288.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_288.png new file mode 100644 index 00000000..24c32e2f Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_288.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_289.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_289.png new file mode 100644 index 00000000..b99df911 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_289.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_290.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_290.png new file mode 100644 index 00000000..643cb958 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_290.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_291.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_291.png new file mode 100644 index 00000000..7b3b3721 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_291.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_292.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_292.png new file mode 100644 index 00000000..c63f1578 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_292.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_293.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_293.png new file mode 100644 index 00000000..c2ebdac9 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_293.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_294.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_294.png new file mode 100644 index 00000000..93eb3830 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_294.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_295.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_295.png new file mode 100644 index 00000000..c3946315 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_295.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_296.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_296.png new file mode 100644 index 00000000..1dc14d32 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_296.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_297.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_297.png new file mode 100644 index 00000000..cf780f96 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_297.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_298.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_298.png new file mode 100644 index 00000000..4304acc3 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_298.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_299.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_299.png new file mode 100644 index 00000000..2adeadbc Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_299.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_300.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_300.png new file mode 100644 index 00000000..20a83689 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_300.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_301.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_301.png new file mode 100644 index 00000000..16ad3f80 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_301.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_302.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_302.png new file mode 100644 index 00000000..f2fa8294 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_302.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_303.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_303.png new file mode 100644 index 00000000..de732f58 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_303.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_304.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_304.png new file mode 100644 index 00000000..9de74a0d Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_304.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_305.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_305.png new file mode 100644 index 00000000..d49f7fe0 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_305.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_306.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_306.png new file mode 100644 index 00000000..25d7a015 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_306.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_307.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_307.png new file mode 100644 index 00000000..50ec1d88 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_307.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_308.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_308.png new file mode 100644 index 00000000..c2e73e0a Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_308.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_309.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_309.png new file mode 100644 index 00000000..ccc5122e Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_309.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_310.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_310.png new file mode 100644 index 00000000..199eca42 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_310.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_311.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_311.png new file mode 100644 index 00000000..3a0b4a42 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_311.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_312.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_312.png new file mode 100644 index 00000000..092f82f7 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_312.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_313.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_313.png new file mode 100644 index 00000000..da589c64 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_313.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_314.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_314.png new file mode 100644 index 00000000..edb808f4 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_314.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_315.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_315.png new file mode 100644 index 00000000..11f2c4d2 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_315.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_316.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_316.png new file mode 100644 index 00000000..7bbb4aa7 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_316.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_317.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_317.png new file mode 100644 index 00000000..fdeff349 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_317.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_318.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_318.png new file mode 100644 index 00000000..3f54793a Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_318.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_319.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_319.png new file mode 100644 index 00000000..58675967 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_319.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_320.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_320.png new file mode 100644 index 00000000..d74eccde Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_320.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_321.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_321.png new file mode 100644 index 00000000..fae6a4e2 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_321.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_322.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_322.png new file mode 100644 index 00000000..e6c32a6a Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_322.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_323.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_323.png new file mode 100644 index 00000000..b3c185f4 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_323.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_324.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_324.png new file mode 100644 index 00000000..7fa71275 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_324.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_325.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_325.png new file mode 100644 index 00000000..c09bf294 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_325.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_326.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_326.png new file mode 100644 index 00000000..bc660f63 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_326.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_327.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_327.png new file mode 100644 index 00000000..42cdc166 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_327.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_328.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_328.png new file mode 100644 index 00000000..bef65532 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_328.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_329.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_329.png new file mode 100644 index 00000000..07460e5c Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_329.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_330.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_330.png new file mode 100644 index 00000000..8bbb2f51 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_330.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_331.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_331.png new file mode 100644 index 00000000..b2a9fab6 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_331.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_332.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_332.png new file mode 100644 index 00000000..69784f54 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_332.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_333.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_333.png new file mode 100644 index 00000000..1ceeb71b Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_333.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_334.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_334.png new file mode 100644 index 00000000..176eb6bd Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_334.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_335.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_335.png new file mode 100644 index 00000000..e10a5977 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_335.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_336.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_336.png new file mode 100644 index 00000000..9eb2a5cd Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_336.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_337.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_337.png new file mode 100644 index 00000000..bc855d70 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_337.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_338.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_338.png new file mode 100644 index 00000000..d898b6f3 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_338.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_339.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_339.png new file mode 100644 index 00000000..952bb29f Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_339.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_340.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_340.png new file mode 100644 index 00000000..f9274fdf Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_340.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_341.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_341.png new file mode 100644 index 00000000..5e19d089 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_341.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_342.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_342.png new file mode 100644 index 00000000..d37cd111 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_342.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_343.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_343.png new file mode 100644 index 00000000..6aa19570 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_343.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_344.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_344.png new file mode 100644 index 00000000..dd1e3ebf Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_344.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_345.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_345.png new file mode 100644 index 00000000..99a125f7 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_345.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_346.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_346.png new file mode 100644 index 00000000..90a5d310 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_346.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_347.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_347.png new file mode 100644 index 00000000..d509ec8c Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_347.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_348.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_348.png new file mode 100644 index 00000000..d2f1f38f Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_348.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_349.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_349.png new file mode 100644 index 00000000..a6a6b35f Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_349.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_350.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_350.png new file mode 100644 index 00000000..ca1df079 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_350.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_351.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_351.png new file mode 100644 index 00000000..ac7421bb Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_351.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_352.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_352.png new file mode 100644 index 00000000..341f5479 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_352.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_353.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_353.png new file mode 100644 index 00000000..fc23aaeb Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_353.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_354.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_354.png new file mode 100644 index 00000000..810aa114 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_354.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_355.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_355.png new file mode 100644 index 00000000..b54f8b18 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_355.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_356.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_356.png new file mode 100644 index 00000000..fe5d112a Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_356.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_357.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_357.png new file mode 100644 index 00000000..00ec87b4 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_357.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_358.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_358.png new file mode 100644 index 00000000..1ee2cbbe Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_358.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_359.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_359.png new file mode 100644 index 00000000..36022459 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_359.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_360.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_360.png new file mode 100644 index 00000000..3cbcd2e6 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_360.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_361.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_361.png new file mode 100644 index 00000000..9e10d86a Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_361.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_362.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_362.png new file mode 100644 index 00000000..1ab8e4a7 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_362.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_363.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_363.png new file mode 100644 index 00000000..583856a9 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_363.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_364.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_364.png new file mode 100644 index 00000000..1a1b591b Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_364.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_365.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_365.png new file mode 100644 index 00000000..6d84c42b Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_365.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_366.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_366.png new file mode 100644 index 00000000..444f3a30 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_366.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_367.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_367.png new file mode 100644 index 00000000..5e96bcca Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_367.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_368.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_368.png new file mode 100644 index 00000000..9142f884 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_368.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_369.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_369.png new file mode 100644 index 00000000..465f59cb Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_369.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_370.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_370.png new file mode 100644 index 00000000..fa49ee52 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_370.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_371.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_371.png new file mode 100644 index 00000000..01030655 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_371.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_372.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_372.png new file mode 100644 index 00000000..804c975c Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_372.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_373.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_373.png new file mode 100644 index 00000000..d09c5e67 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_373.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_374.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_374.png new file mode 100644 index 00000000..8fb5fee6 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_374.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_375.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_375.png new file mode 100644 index 00000000..aaf996a6 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_375.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_376.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_376.png new file mode 100644 index 00000000..516dafed Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_376.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_377.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_377.png new file mode 100644 index 00000000..ee07a541 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_377.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_378.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_378.png new file mode 100644 index 00000000..d48765b6 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_378.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_379.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_379.png new file mode 100644 index 00000000..f1797029 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_379.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_380.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_380.png new file mode 100644 index 00000000..82d37c40 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_380.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_381.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_381.png new file mode 100644 index 00000000..a9f3ccc4 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_381.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_382.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_382.png new file mode 100644 index 00000000..4e1e404e Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_382.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_383.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_383.png new file mode 100644 index 00000000..b5c9add3 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_383.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_384.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_384.png new file mode 100644 index 00000000..a401d704 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_384.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_385.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_385.png new file mode 100644 index 00000000..f03a5a2d Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_385.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_386.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_386.png new file mode 100644 index 00000000..8c74cdb3 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_386.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_387.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_387.png new file mode 100644 index 00000000..3f4e39a6 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_387.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_388.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_388.png new file mode 100644 index 00000000..28e7db72 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_388.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_389.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_389.png new file mode 100644 index 00000000..3c97bc36 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_389.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_390.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_390.png new file mode 100644 index 00000000..df113a39 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_390.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_391.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_391.png new file mode 100644 index 00000000..f2b19f92 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_391.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_392.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_392.png new file mode 100644 index 00000000..6af29fa4 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_392.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_393.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_393.png new file mode 100644 index 00000000..dd23d860 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_393.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_394.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_394.png new file mode 100644 index 00000000..e99067ac Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_394.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_395.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_395.png new file mode 100644 index 00000000..f4943032 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_395.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_396.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_396.png new file mode 100644 index 00000000..8617d8ac Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_396.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_397.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_397.png new file mode 100644 index 00000000..5a702351 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_397.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_398.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_398.png new file mode 100644 index 00000000..224c65dd Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_398.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_399.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_399.png new file mode 100644 index 00000000..c4fa5e08 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_399.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_400.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_400.png new file mode 100644 index 00000000..8b12cecd Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_400.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_401.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_401.png new file mode 100644 index 00000000..33870931 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_401.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_402.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_402.png new file mode 100644 index 00000000..c632399c Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_402.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_403.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_403.png new file mode 100644 index 00000000..68b70737 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_403.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_404.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_404.png new file mode 100644 index 00000000..cd044982 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_404.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_405.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_405.png new file mode 100644 index 00000000..dc29fddc Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_405.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_406.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_406.png new file mode 100644 index 00000000..13bbabbd Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_406.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_407.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_407.png new file mode 100644 index 00000000..f484b9c0 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_407.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_408.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_408.png new file mode 100644 index 00000000..8bacc001 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_408.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_409.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_409.png new file mode 100644 index 00000000..7e67337c Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_409.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_410.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_410.png new file mode 100644 index 00000000..d7cadec0 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_410.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_411.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_411.png new file mode 100644 index 00000000..b70c257c Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_411.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_412.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_412.png new file mode 100644 index 00000000..f38a8e25 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_412.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_413.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_413.png new file mode 100644 index 00000000..d29656e1 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_413.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_414.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_414.png new file mode 100644 index 00000000..65dfecc6 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_414.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_415.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_415.png new file mode 100644 index 00000000..2b7067f5 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_415.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_416.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_416.png new file mode 100644 index 00000000..b90f2932 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_416.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_417.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_417.png new file mode 100644 index 00000000..37f667b3 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_417.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_418.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_418.png new file mode 100644 index 00000000..b2d374c5 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_418.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_419.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_419.png new file mode 100644 index 00000000..67e14be7 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_419.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_420.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_420.png new file mode 100644 index 00000000..0cb08e35 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_420.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_421.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_421.png new file mode 100644 index 00000000..390d9d35 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_421.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_422.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_422.png new file mode 100644 index 00000000..381ad462 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_422.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_423.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_423.png new file mode 100644 index 00000000..4b3020c7 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_423.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_424.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_424.png new file mode 100644 index 00000000..9f43ffba Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_424.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_425.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_425.png new file mode 100644 index 00000000..d0af83ef Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_425.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_426.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_426.png new file mode 100644 index 00000000..d44614cd Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_426.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_427.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_427.png new file mode 100644 index 00000000..c7410e61 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_427.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_428.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_428.png new file mode 100644 index 00000000..6e129a81 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_428.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_429.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_429.png new file mode 100644 index 00000000..3378d5c9 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_429.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_430.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_430.png new file mode 100644 index 00000000..8bdd9d7e Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_430.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_431.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_431.png new file mode 100644 index 00000000..619eb46a Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_431.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_432.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_432.png new file mode 100644 index 00000000..7124bba3 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_432.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_433.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_433.png new file mode 100644 index 00000000..a2aed810 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_433.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_434.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_434.png new file mode 100644 index 00000000..dfe70467 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_434.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_435.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_435.png new file mode 100644 index 00000000..016ae71f Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_435.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_436.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_436.png new file mode 100644 index 00000000..57507e79 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_436.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_437.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_437.png new file mode 100644 index 00000000..a5ecb675 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_437.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_438.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_438.png new file mode 100644 index 00000000..189b1fdf Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_438.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_439.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_439.png new file mode 100644 index 00000000..ec4e1bea Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_439.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_440.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_440.png new file mode 100644 index 00000000..23a76e2c Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_440.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_441.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_441.png new file mode 100644 index 00000000..1e0b3893 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_441.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_442.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_442.png new file mode 100644 index 00000000..4562e165 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_442.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_443.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_443.png new file mode 100644 index 00000000..8b9ac34b Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_443.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_444.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_444.png new file mode 100644 index 00000000..d99eeb0c Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_444.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_445.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_445.png new file mode 100644 index 00000000..4703e361 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_445.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_446.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_446.png new file mode 100644 index 00000000..36c66852 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_446.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_447.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_447.png new file mode 100644 index 00000000..48d6cfc8 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_447.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_448.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_448.png new file mode 100644 index 00000000..c00cbb19 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_448.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_449.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_449.png new file mode 100644 index 00000000..d31e59a2 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_449.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_450.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_450.png new file mode 100644 index 00000000..c3389129 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_450.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_451.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_451.png new file mode 100644 index 00000000..cb6dbbf7 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_451.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_452.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_452.png new file mode 100644 index 00000000..ca7571bf Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_452.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_453.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_453.png new file mode 100644 index 00000000..322a29d7 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_453.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_454.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_454.png new file mode 100644 index 00000000..4b79a696 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_454.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_455.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_455.png new file mode 100644 index 00000000..9f3f2475 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_455.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_456.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_456.png new file mode 100644 index 00000000..ab73991b Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_456.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_457.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_457.png new file mode 100644 index 00000000..5b0e6ced Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_457.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_458.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_458.png new file mode 100644 index 00000000..27b57fe1 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_458.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_459.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_459.png new file mode 100644 index 00000000..ef2d43a2 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_459.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_460.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_460.png new file mode 100644 index 00000000..0202960f Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_460.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_461.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_461.png new file mode 100644 index 00000000..ff4b5bb2 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_461.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_462.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_462.png new file mode 100644 index 00000000..156c7904 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_462.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_463.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_463.png new file mode 100644 index 00000000..84f7d9de Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_463.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_464.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_464.png new file mode 100644 index 00000000..adcdb9bd Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_464.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_465.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_465.png new file mode 100644 index 00000000..3615e86f Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_465.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_466.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_466.png new file mode 100644 index 00000000..554a15d9 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_466.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_467.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_467.png new file mode 100644 index 00000000..409e60dc Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_467.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_468.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_468.png new file mode 100644 index 00000000..43ae465d Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_468.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_469.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_469.png new file mode 100644 index 00000000..e08e79fc Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_469.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_470.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_470.png new file mode 100644 index 00000000..c4d12930 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_470.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_471.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_471.png new file mode 100644 index 00000000..ad383b0e Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_471.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_472.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_472.png new file mode 100644 index 00000000..0922e9a1 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_472.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_473.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_473.png new file mode 100644 index 00000000..a67f4d1d Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_473.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_474.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_474.png new file mode 100644 index 00000000..629154a4 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_474.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_475.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_475.png new file mode 100644 index 00000000..f01aea97 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_475.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_476.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_476.png new file mode 100644 index 00000000..ddd230e4 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_476.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_477.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_477.png new file mode 100644 index 00000000..84907471 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_477.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_478.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_478.png new file mode 100644 index 00000000..4665c67f Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_478.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_479.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_479.png new file mode 100644 index 00000000..d684ed55 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_479.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_480.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_480.png new file mode 100644 index 00000000..2fe4660f Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_480.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_481.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_481.png new file mode 100644 index 00000000..b4a72280 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_481.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_482.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_482.png new file mode 100644 index 00000000..116c6747 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_482.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_483.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_483.png new file mode 100644 index 00000000..eaf8e6db Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_483.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_484.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_484.png new file mode 100644 index 00000000..e73ecc9a Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_484.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_485.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_485.png new file mode 100644 index 00000000..8a1f0d1b Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_485.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_486.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_486.png new file mode 100644 index 00000000..ba94bf66 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_486.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_487.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_487.png new file mode 100644 index 00000000..c12ff684 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_487.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_488.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_488.png new file mode 100644 index 00000000..dede6041 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_488.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_489.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_489.png new file mode 100644 index 00000000..bd2ff02f Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_489.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_490.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_490.png new file mode 100644 index 00000000..b68a6a9a Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_490.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_491.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_491.png new file mode 100644 index 00000000..25b2d62d Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_491.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_492.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_492.png new file mode 100644 index 00000000..8ab7a314 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_492.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_493.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_493.png new file mode 100644 index 00000000..df8d727d Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_493.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_494.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_494.png new file mode 100644 index 00000000..751e0111 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_494.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_495.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_495.png new file mode 100644 index 00000000..fcb895c6 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_495.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_496.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_496.png new file mode 100644 index 00000000..7b54d910 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_496.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_497.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_497.png new file mode 100644 index 00000000..ba285312 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_497.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_498.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_498.png new file mode 100644 index 00000000..3c26f90b Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_498.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_499.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_499.png new file mode 100644 index 00000000..7f151a2f Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_499.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_500.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_500.png new file mode 100644 index 00000000..f49bfd7b Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_500.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_501.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_501.png new file mode 100644 index 00000000..16a61f4d Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_501.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_502.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_502.png new file mode 100644 index 00000000..069336da Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_502.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_503.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_503.png new file mode 100644 index 00000000..1545fe7f Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_503.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_504.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_504.png new file mode 100644 index 00000000..bff7dc40 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_504.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_505.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_505.png new file mode 100644 index 00000000..5b127e10 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_505.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_506.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_506.png new file mode 100644 index 00000000..9eb9e205 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_506.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_507.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_507.png new file mode 100644 index 00000000..977cfdfb Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_507.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_508.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_508.png new file mode 100644 index 00000000..38438a42 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_508.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_509.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_509.png new file mode 100644 index 00000000..ef7d616a Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_509.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_510.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_510.png new file mode 100644 index 00000000..a76f6aad Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_510.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_511.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_511.png new file mode 100644 index 00000000..be41101b Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_511.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_512.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_512.png new file mode 100644 index 00000000..b24d3fe3 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_512.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_513.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_513.png new file mode 100644 index 00000000..d18e4871 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_513.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_514.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_514.png new file mode 100644 index 00000000..85ba060f Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_514.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_515.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_515.png new file mode 100644 index 00000000..61831380 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_515.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_516.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_516.png new file mode 100644 index 00000000..41fc665f Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_516.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_517.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_517.png new file mode 100644 index 00000000..c89e181c Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_517.png differ diff --git a/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_518.png b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_518.png new file mode 100644 index 00000000..6cad7931 Binary files /dev/null and b/packages/media/tests/pdf/MS300-Manual-Compact/MS300-Manual-Compact_518.png differ