diff --git a/src/cli/cli.ts b/src/cli/cli.ts index ac38b52..300da20 100644 --- a/src/cli/cli.ts +++ b/src/cli/cli.ts @@ -88,22 +88,33 @@ program program .command("pack [directory] [output]") .description("Pack a directory into an MCPB extension") - .action((directory: string = process.cwd(), output?: string) => { - void (async () => { - try { - const success = await packExtension({ - extensionPath: directory, - outputPath: output, - }); - process.exit(success ? 0 : 1); - } catch (error) { - console.error( - `ERROR: ${error instanceof Error ? error.message : "Unknown error"}`, - ); - process.exit(1); - } - })(); - }); + .option( + "--manifest-version ", + "Override manifest version in the output bundle", + ) + .action( + ( + directory: string = process.cwd(), + output?: string, + options?: { manifestVersion?: string }, + ) => { + void (async () => { + try { + const success = await packExtension({ + extensionPath: directory, + outputPath: output, + manifestVersion: options?.manifestVersion, + }); + process.exit(success ? 0 : 1); + } catch (error) { + console.error( + `ERROR: ${error instanceof Error ? error.message : "Unknown error"}`, + ); + process.exit(1); + } + })(); + }, + ); // Unpack command program diff --git a/src/cli/pack.ts b/src/cli/pack.ts index e2411bf..ef3c45a 100644 --- a/src/cli/pack.ts +++ b/src/cli/pack.ts @@ -22,6 +22,7 @@ interface PackOptions { extensionPath: string; outputPath?: string; silent?: boolean; + manifestVersion?: string; } function formatFileSize(bytes: number): string { @@ -50,10 +51,22 @@ export async function packExtension({ extensionPath, outputPath, silent, + manifestVersion: targetManifestVersion, }: PackOptions): Promise { const resolvedPath = resolve(extensionPath); const logger = getLogger({ silent }); + // Validate target manifest version if provided + if ( + targetManifestVersion && + !(targetManifestVersion in MANIFEST_SCHEMAS) + ) { + logger.error( + `ERROR: Invalid manifest version "${targetManifestVersion}". Supported versions: ${Object.keys(MANIFEST_SCHEMAS).join(", ")}`, + ); + return false; + } + // Check if directory exists if (!existsSync(resolvedPath) || !statSync(resolvedPath).isDirectory()) { logger.error(`ERROR: Directory not found: ${extensionPath}`); @@ -90,10 +103,11 @@ export async function packExtension({ // Read and parse manifest let manifest; + let finalManifestContent: string; try { const manifestContent = readFileSync(manifestPath, "utf-8"); const manifestData = JSON.parse(manifestContent); - const manifestVersion = getManifestVersionFromRawData(manifestData); + let manifestVersion = getManifestVersionFromRawData(manifestData); if (!manifestVersion) { logger.error( `ERROR: Manifest version mismatch. Expected "${Object.keys(MANIFEST_SCHEMAS).join(" or ")}", found "${manifestVersion}"`, @@ -104,7 +118,20 @@ export async function packExtension({ return false; } + // Override manifest version if target version is specified + if (targetManifestVersion && targetManifestVersion !== manifestVersion) { + logger.log( + `Overriding manifest version from ${manifestVersion} to ${targetManifestVersion}`, + ); + manifestData.manifest_version = targetManifestVersion; + // Remove legacy dxt_version if present to avoid confusion + delete manifestData.dxt_version; + manifestVersion = + targetManifestVersion as keyof typeof MANIFEST_SCHEMAS; + } + manifest = MANIFEST_SCHEMAS[manifestVersion].parse(manifestData); + finalManifestContent = JSON.stringify(manifestData, null, 2); } catch (error) { logger.error("ERROR: Failed to parse manifest.json"); if (error instanceof Error) { @@ -135,6 +162,14 @@ export async function packExtension({ mcpbIgnorePatterns, ); + // Override manifest.json with potentially modified content (version override) + if (files[manifestPath]) { + files[manifestPath] = { + ...files[manifestPath], + data: Buffer.from(finalManifestContent, "utf-8"), + }; + } + // Print package header logger.log(`\n📦 ${manifest.name}@${manifest.version}`);