Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -99,4 +99,4 @@
"@babel/parser": "7.27.3"
},
"packageManager": "[email protected]+sha512.c38cafb5c7bb273f3926d04e55e1d8c9dfa7d9c3ea1f36a4868fa028b9e5f72298f0b7f401ad5eb921749eb012eb1c3bb74bf7503df3ee43fd600d14a018266f"
}
}
8 changes: 4 additions & 4 deletions src/cli/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import { confirm, input, select } from "@inquirer/prompts";
import { existsSync, readFileSync, writeFileSync } from "fs";
import { basename, join, resolve } from "path";

import { LATEST_MANIFEST_VERSION } from "../shared/constants.js";
import type { McpbManifestLatest } from "../types.js";
import { DEFAULT_MANIFEST_VERSION } from "../shared/constants.js";
import type { McpbManifest } from "../types.js";

interface PackageJson {
name?: string;
Expand Down Expand Up @@ -878,14 +878,14 @@ export function buildManifest(
resources: string;
default_locale: string;
},
): McpbManifestLatest {
): McpbManifest {
const { name, displayName, version, description, authorName } = basicInfo;
const { authorEmail, authorUrl } = authorInfo;
const { serverType, entryPoint, mcp_config } = serverConfig;
const { keywords, license, repository } = optionalFields;

return {
manifest_version: LATEST_MANIFEST_VERSION,
manifest_version: DEFAULT_MANIFEST_VERSION,
name,
...(displayName && displayName !== name
? { display_name: displayName }
Expand Down
30 changes: 14 additions & 16 deletions src/cli/pack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,9 @@ import { basename, join, relative, resolve, sep } from "path";

import { getAllFilesWithCount, readMcpbIgnorePatterns } from "../node/files.js";
import { validateManifest } from "../node/validate.js";
import {
LATEST_MANIFEST_SCHEMA,
LATEST_MANIFEST_VERSION,
} from "../shared/constants.js";
import { MANIFEST_SCHEMAS } from "../shared/constants.js";
import { getLogger } from "../shared/log.js";
import { getManifestVersionFromRawData } from "../shared/manifestVersionResolve.js";
import { initExtension } from "./init.js";

interface PackOptions {
Expand Down Expand Up @@ -95,7 +93,18 @@ export async function packExtension({
try {
const manifestContent = readFileSync(manifestPath, "utf-8");
const manifestData = JSON.parse(manifestContent);
manifest = LATEST_MANIFEST_SCHEMA.parse(manifestData);
const manifestVersion = getManifestVersionFromRawData(manifestData);
if (!manifestVersion) {
logger.error(
`ERROR: Manifest version mismatch. Expected "${Object.keys(MANIFEST_SCHEMAS).join(" or ")}", found "${manifestVersion}"`,
);
logger.error(
` Please update the manifest_version in your manifest.json to a supported version`,
);
return false;
}

manifest = MANIFEST_SCHEMAS[manifestVersion].parse(manifestData);
} catch (error) {
logger.error("ERROR: Failed to parse manifest.json");
if (error instanceof Error) {
Expand All @@ -104,17 +113,6 @@ export async function packExtension({
return false;
}

const manifestVersion = manifest.manifest_version || manifest.dxt_version;
if (manifestVersion !== LATEST_MANIFEST_VERSION) {
logger.error(
`ERROR: Manifest version mismatch. Expected "${LATEST_MANIFEST_VERSION}", found "${manifestVersion}"`,
);
logger.error(
` Please update the manifest_version in your manifest.json to "${LATEST_MANIFEST_VERSION}"`,
);
return false;
}

// Determine output path
const extensionName = basename(resolvedPath);
const finalOutputPath = outputPath
Expand Down
19 changes: 15 additions & 4 deletions src/node/validate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ import prettyBytes from "pretty-bytes";

import { unpackExtension } from "../cli/unpack.js";
import {
LATEST_MANIFEST_SCHEMA,
LATEST_MANIFEST_SCHEMA_LOOSE,
MANIFEST_SCHEMAS,
MANIFEST_SCHEMAS_LOOSE,
} from "../shared/constants.js";
import { getManifestVersionFromRawData } from "../shared/manifestVersionResolve.js";

/**
* Check if a buffer contains a valid PNG file signature
Expand Down Expand Up @@ -119,8 +120,13 @@ export function validateManifest(inputPath: string): boolean {

const manifestContent = readFileSync(manifestPath, "utf-8");
const manifestData = JSON.parse(manifestContent);
const manifestVersion = getManifestVersionFromRawData(manifestData);
if (!manifestVersion) {
console.log("Unrecognized or unsupported manifest version");
return false;
}

const result = LATEST_MANIFEST_SCHEMA.safeParse(manifestData);
const result = MANIFEST_SCHEMAS[manifestVersion].safeParse(manifestData);

if (result.success) {
console.log("Manifest schema validation passes!");
Expand Down Expand Up @@ -192,7 +198,12 @@ export async function cleanMcpb(inputPath: string) {
const manifestPath = resolve(unpackPath, "manifest.json");
const originalManifest = await fs.readFile(manifestPath, "utf-8");
const manifestData = JSON.parse(originalManifest);
const result = LATEST_MANIFEST_SCHEMA_LOOSE.safeParse(manifestData);
const manifestVersion = getManifestVersionFromRawData(manifestData);
if (!manifestVersion) {
throw new Error("Unrecognized or unsupported manifest version");
}
const result =
MANIFEST_SCHEMAS_LOOSE[manifestVersion].safeParse(manifestData);

if (!result.success) {
throw new Error(
Expand Down
8 changes: 8 additions & 0 deletions src/shared/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,15 @@ import { McpbManifestSchema as CurrentLooseManifestSchema } from "../schemas_loo

/**
* Latest manifest version - the version that new manifests should use
* @deprecated
*/
export const LATEST_MANIFEST_VERSION = "0.3" as const;

/**
* Default manifest version for new packages
*/
export const DEFAULT_MANIFEST_VERSION = "0.2" as const;

/**
* Map of manifest versions to their strict schemas
*/
Expand All @@ -32,10 +38,12 @@ export const MANIFEST_SCHEMAS_LOOSE = {

/**
* Get the latest manifest schema based on LATEST_MANIFEST_VERSION
* @deprecated
*/
export const LATEST_MANIFEST_SCHEMA = CurrentManifestSchema;

/**
* Get the latest loose manifest schema based on LATEST_MANIFEST_VERSION
* @deprecated
*/
export const LATEST_MANIFEST_SCHEMA_LOOSE = CurrentLooseManifestSchema;
24 changes: 24 additions & 0 deletions src/shared/manifestVersionResolve.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { MANIFEST_SCHEMAS } from "./constants.js";

export function getManifestVersionFromRawData(manifestData: unknown) {
let manifestVersion: keyof typeof MANIFEST_SCHEMAS | null = null;
if (
typeof manifestData === "object" &&
manifestData &&
"manifest_version" in manifestData &&
typeof manifestData.manifest_version === "string" &&
Object.keys(MANIFEST_SCHEMAS).includes(manifestData.manifest_version)
) {
manifestVersion =
manifestData.manifest_version as keyof typeof MANIFEST_SCHEMAS;
} else if (
typeof manifestData === "object" &&
manifestData &&
"dxt_version" in manifestData &&
typeof manifestData.dxt_version === "string" &&
Object.keys(MANIFEST_SCHEMAS).includes(manifestData.dxt_version)
) {
manifestVersion = manifestData.dxt_version as keyof typeof MANIFEST_SCHEMAS;
}
return manifestVersion;
}
10 changes: 5 additions & 5 deletions test/cli.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { execSync } from "node:child_process";
import fs from "node:fs";
import { join } from "node:path";

import { LATEST_MANIFEST_VERSION } from "../src/schemas/index.js";
import { DEFAULT_MANIFEST_VERSION } from "../src/shared/constants";

interface ExecSyncError extends Error {
stdout: Buffer;
Expand Down Expand Up @@ -113,7 +113,7 @@ describe("DXT CLI", () => {
fs.writeFileSync(
manifestWithIcon,
JSON.stringify({
manifest_version: LATEST_MANIFEST_VERSION,
manifest_version: DEFAULT_MANIFEST_VERSION,
name: "test-with-icon",
version: "1.0.0",
description: "Test with icon",
Expand All @@ -140,7 +140,7 @@ describe("DXT CLI", () => {
fs.writeFileSync(
manifestWithUrl,
JSON.stringify({
manifest_version: LATEST_MANIFEST_VERSION,
manifest_version: DEFAULT_MANIFEST_VERSION,
name: "test-with-url",
version: "1.0.0",
description: "Test with URL",
Expand Down Expand Up @@ -177,7 +177,7 @@ describe("DXT CLI", () => {
fs.writeFileSync(
join(tempDir, "manifest.json"),
JSON.stringify({
manifest_version: LATEST_MANIFEST_VERSION,
manifest_version: DEFAULT_MANIFEST_VERSION,
name: "Test Extension",
version: "1.0.0",
description: "A test extension",
Expand Down Expand Up @@ -274,7 +274,7 @@ describe("DXT CLI", () => {
fs.writeFileSync(
join(tempExecDir, "manifest.json"),
JSON.stringify({
manifest_version: LATEST_MANIFEST_VERSION,
manifest_version: DEFAULT_MANIFEST_VERSION,
name: "Test Executable Extension",
version: "1.0.0",
description: "A test extension with executable files",
Expand Down
6 changes: 3 additions & 3 deletions test/init.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
getDefaultRepositoryUrl,
readPackageJson,
} from "../src/cli/init.js";
import { LATEST_MANIFEST_VERSION } from "../src/schemas/index.js";
import { DEFAULT_MANIFEST_VERSION } from "../src/shared/constants.js";

// Mock the fs module
jest.mock("fs", () => ({
Expand Down Expand Up @@ -220,7 +220,7 @@ describe("init functions", () => {
);

expect(manifest).toEqual({
manifest_version: LATEST_MANIFEST_VERSION,
manifest_version: DEFAULT_MANIFEST_VERSION,
name: "test-extension",
version: "1.0.0",
description: "Test description",
Expand Down Expand Up @@ -322,7 +322,7 @@ describe("init functions", () => {
);

expect(manifest).toEqual({
manifest_version: LATEST_MANIFEST_VERSION,
manifest_version: DEFAULT_MANIFEST_VERSION,
name: "test-extension",
display_name: "Test Extension",
version: "1.0.0",
Expand Down