import { tool } from "@lmstudio/sdk";
import { z } from "zod";
import { zipCreate, zipExtract, zipList } from "../fileUtilities";
import { sanitizeFilePath, validateWritePath } from "../securityEnhanced";
import { logger } from "../logger";
export async function registerArchiveTools(): Promise<any[]> {
const tools: any[] = [];
tools.push(tool({
name: "zip_create",
description: "Create a .zip archive.",
parameters: {
entries: z.array(z.object({
source: z.string().describe("Source path"),
name: z.string().describe("Name in archive"),
})).describe("List of files/directories"),
output_path: z.string().describe("Output .zip path"),
},
implementation: async ({ entries, output_path }) => {
// Validate output path with system protection
const outValidation = validateWritePath(output_path);
if (!outValidation.valid) {
return { success: false, output_path, files_count: 0, total_uncompressed_size: 0, compressed_size: 0, compression_ratio: "0%", error: outValidation.error };
}
// Validate each source entry (read-only, use sanitizeFilePath)
for (const entry of entries) {
const srcValidation = sanitizeFilePath(entry.source);
if (!srcValidation.valid) {
return { success: false, output_path, files_count: 0, total_uncompressed_size: 0, compressed_size: 0, compression_ratio: "0%", error: `Source file '${entry.source}': ${srcValidation.error}` };
}
}
const result = zipCreate(entries, outValidation.sanitized!);
return {
success: result.success,
output_path: result.outputPath,
files_count: result.filesCount,
total_uncompressed_size: result.totalUncompressedSize,
compressed_size: result.compressedSize,
compression_ratio: result.totalUncompressedSize > 0
? ((1 - result.compressedSize / result.totalUncompressedSize) * 100).toFixed(2) + "%"
: "0%",
error: result.error,
};
},
}));
tools.push(tool({
name: "zip_extract",
description: "Extract a .zip archive.",
parameters: {
zip_path: z.string().describe("Path to zip"),
dest_dir: z.string().describe("Destination directory"),
},
implementation: async ({ zip_path, dest_dir }) => {
const zipValidation = sanitizeFilePath(zip_path);
if (!zipValidation.valid) {
return { success: false, extracted_files: [], files_count: 0, error: zipValidation.error };
}
const destValidation = validateWritePath(dest_dir);
if (!destValidation.valid) {
return { success: false, extracted_files: [], files_count: 0, error: destValidation.error };
}
const result = zipExtract(zipValidation.sanitized!, destValidation.sanitized!);
return {
success: result.success,
extracted_files: result.extractedFiles,
files_count: result.extractedFiles.length,
error: result.error,
};
},
}));
tools.push(tool({
name: "zip_list",
description: "List contents of a .zip archive.",
parameters: { zip_path: z.string().describe("Path to zip") },
implementation: async ({ zip_path }) => {
const validation = sanitizeFilePath(zip_path);
if (!validation.valid) {
return { success: false, entries: [], entry_count: 0, total_compressed_size: 0, total_uncompressed_size: 0, overall_compression_ratio: "0%", error: validation.error };
}
const result = zipList(validation.sanitized!);
if (!result.success) return { success: false, entries: [], entry_count: 0, total_compressed_size: 0, total_uncompressed_size: 0, overall_compression_ratio: "0%", error: result.error };
const entries = result.entries.map((e) => ({
name: e.name,
compressed_size: e.compressedSize,
uncompressed_size: e.uncompressedSize,
is_directory: e.isDirectory,
compression_ratio: e.uncompressedSize > 0
? (((1 - e.compressedSize / e.uncompressedSize) * 100).toFixed(2) + "%")
: "N/A",
}));
const totalCompressed = result.entries.reduce((s, e) => s + e.compressedSize, 0);
const totalUncompressed = result.entries.reduce((s, e) => s + e.uncompressedSize, 0);
return {
success: true,
entries,
entry_count: result.entries.length,
total_compressed_size: totalCompressed,
total_uncompressed_size: totalUncompressed,
overall_compression_ratio: totalUncompressed > 0
? ((1 - totalCompressed / totalUncompressed) * 100).toFixed(2) + "%"
: "0%",
};
},
}));
return tools;
}