@nuwa-ai/cap-kit
Version:
731 lines (725 loc) • 23.1 kB
JavaScript
;
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var index_exports = {};
__export(index_exports, {
CapArtifactSchema: () => CapArtifactSchema,
CapAuthorDIDSchema: () => CapAuthorDIDSchema,
CapCoreSchema: () => CapCoreSchema,
CapIDNameSchema: () => CapIDNameSchema,
CapIDSchema: () => CapIDSchema,
CapKitMcp: () => CapKitMcp,
CapKitRestful: () => CapKitRestful,
CapMcpServerSchema: () => CapMcpServerSchema,
CapMetadataSchema: () => CapMetadataSchema,
CapModelSchema: () => CapModelSchema,
CapPromptSchema: () => CapPromptSchema,
CapPromptSuggestionSchema: () => CapPromptSuggestionSchema,
CapSchema: () => CapSchema,
CapStatsSchema: () => CapStatsSchema,
CapThumbnailSchema: () => CapThumbnailSchema,
RatingDistribution: () => RatingDistribution,
ResultCapMetadataSchema: () => ResultCapMetadataSchema
});
module.exports = __toCommonJS(index_exports);
// src/type.ts
var import_v3 = require("zod/v3");
var CapAuthorDIDSchema = import_v3.z.string().startsWith("did:");
var CapIDNameSchema = import_v3.z.string().regex(/^[a-z0-9_]+$/, "Name must contain only lowercase letters, numbers, and underscores").min(6, "Name must be at least 6 characters").max(20, "Name must be at most 20 characters");
var CapArtifactSchema = import_v3.z.object({
srcUrl: import_v3.z.string().url("Must be a valid URL")
});
var CapIDSchema = import_v3.z.object({
authorDID: CapAuthorDIDSchema,
idName: CapIDNameSchema
}).transform((data) => ({
...data,
id: `${data.authorDID}:${data.idName}`
}));
var CapModelSchema = import_v3.z.object({
customGatewayUrl: import_v3.z.string().url("Must be a valid URL").optional(),
providerId: import_v3.z.enum([
"openai_chat_completion",
"openai_responses",
"anthropic",
"google",
"openrouter",
"xai",
"groq",
"togetherai",
"azure",
"deepseek",
"mistral"
]),
modelId: import_v3.z.string().max(50, "Model ID must be at most 50 characters").refine((id) => id.length > 0, "Model ID is required"),
parameters: import_v3.z.record(import_v3.z.string(), import_v3.z.any()).optional(),
supportedInputs: import_v3.z.array(import_v3.z.enum(["text", "image", "file", "audio"])).min(1).refine((inputs) => inputs.includes("text"), "text input is required"),
contextLength: import_v3.z.number().min(1e3, "Please enter a valid context length")
});
var CapPromptSuggestionSchema = import_v3.z.string().max(100, "Each suggestion must be at most 50 characters");
var CapPromptSchema = import_v3.z.object({
value: import_v3.z.string(),
suggestions: import_v3.z.array(CapPromptSuggestionSchema).optional()
});
var CapMcpServerSchema = import_v3.z.string().url("Must be a valid URL");
var CapCoreSchema = import_v3.z.object({
prompt: CapPromptSchema,
model: CapModelSchema,
mcpServers: import_v3.z.record(import_v3.z.string(), CapMcpServerSchema),
artifact: CapArtifactSchema.optional()
});
var CapThumbnailSchema = import_v3.z.string().url("Must be a valid URL").optional();
var CapMetadataSchema = import_v3.z.object({
displayName: import_v3.z.string().min(1, "Display name is required").max(50, "Display name too long"),
description: import_v3.z.string().min(10, "Description must be at least 10 characters").max(150, "Description too long"),
introduction: import_v3.z.string().min(10, "Introduction must be at least 10 characters").max(5e3, "Introduction too long"),
tags: import_v3.z.array(import_v3.z.string()).min(1, "At least one tag is required"),
homepage: import_v3.z.string().url("Must be a valid URL").optional(),
repository: import_v3.z.string().url("Must be a valid URL").optional(),
thumbnail: CapThumbnailSchema
});
var CapSchema = CapIDSchema.and(
import_v3.z.object({
core: CapCoreSchema,
metadata: CapMetadataSchema
})
);
var CapStatsSchema = import_v3.z.object({
capId: import_v3.z.string(),
downloads: import_v3.z.number(),
ratingCount: import_v3.z.number(),
averageRating: import_v3.z.number(),
favorites: import_v3.z.number(),
userRating: import_v3.z.number().optional()
});
var ResultCapMetadataSchema = import_v3.z.object({
id: import_v3.z.string(),
cid: import_v3.z.string(),
name: import_v3.z.string(),
version: import_v3.z.string(),
displayName: import_v3.z.string(),
description: import_v3.z.string(),
introduction: import_v3.z.string(),
timestamp: import_v3.z.string(),
tags: import_v3.z.array(import_v3.z.string()),
homepage: import_v3.z.string().optional(),
repository: import_v3.z.string().optional(),
thumbnail: CapThumbnailSchema,
stats: CapStatsSchema
});
var RatingDistribution = import_v3.z.object({
rating: import_v3.z.number(),
count: import_v3.z.number()
});
// src/mcp.ts
var import_rooch_sdk = require("@roochnetwork/rooch-sdk");
var yaml = __toESM(require("js-yaml"), 1);
// src/client.ts
var import_payment_kit = require("@nuwa-ai/payment-kit");
var buildClient = async (mcpUrl, env) => {
return (0, import_payment_kit.createMcpClient)({
baseUrl: mcpUrl,
env,
maxAmount: BigInt(1e7),
debug: false,
forceMode: "payment"
});
};
// src/mcp.ts
var CapKitMcp = class {
constructor(option) {
this.isInitializing = false;
this.roochClient = new import_rooch_sdk.RoochClient({ url: option.roochUrl });
this.contractAddress = option.contractAddress;
this.mcpUrl = option.mcpUrl;
this.env = option.env;
}
async getTools() {
if (!this.mcpTools) {
const client = await this.getMcpClient();
this.mcpTools = await client.tools();
}
return this.mcpTools;
}
async getMcpClient() {
if (this.mcpClient) {
return this.mcpClient;
}
while (this.isInitializing) {
await new Promise((resolve) => setTimeout(resolve, 50));
if (this.mcpClient) {
return this.mcpClient;
}
}
this.isInitializing = true;
try {
const client = await buildClient(this.mcpUrl, this.env);
await client.listTools();
this.mcpClient = client;
return client;
} catch (error) {
console.error("Failed to initialize MCP client:", error);
throw error;
} finally {
this.isInitializing = false;
}
}
async mcpClose() {
this.mcpClient?.close();
}
async queryByID(id) {
try {
const tools = await this.getTools();
const queryCapByID = tools.queryCapByID;
if (!queryCapByID) {
throw new Error("Query Cap by id tool not available on MCP server");
}
const result = await queryCapByID.execute(id, {
toolCallId: "queryCapByID",
messages: []
});
if (result.isError) {
throw new Error(result.content?.[0]?.text || "Unknown error");
}
const queryResult = JSON.parse(result.content[0].text);
if (queryResult.code !== 200 && queryResult.code !== 404) {
throw new Error(`Query with id failed: ${queryResult.error || "Unknown error"}`);
}
return queryResult;
} catch (e) {
throw e;
}
}
async queryByName(name, opt) {
try {
const tools = await this.getTools();
const queryCapByName = tools.queryCapByName;
if (!queryCapByName) {
throw new Error("query tool not available on MCP server");
}
const result = await queryCapByName.execute(
{
name,
tags: opt?.tags,
page: opt?.page,
pageSize: opt?.size,
sortBy: opt?.sortBy,
sortOrder: opt?.sortOrder
},
{
toolCallId: "query-cap-by-name",
messages: []
}
);
if (result.isError) {
throw new Error(result.content?.[0]?.text || "Unknown error");
}
const queryResult = JSON.parse(result.content[0].text);
if (queryResult.code === 404) {
return {
code: 200,
data: {
totalItems: 0,
page: opt?.page || 0,
pageSize: opt?.size || 50,
items: []
}
};
}
if (queryResult.code !== 200) {
throw new Error(`query failed: ${queryResult.error || "Unknown error"}`);
}
return {
code: queryResult.code,
data: {
totalItems: queryResult.data.totalItems,
page: queryResult.data.page,
pageSize: queryResult.data.pageSize,
items: queryResult.data.items
}
};
} catch (e) {
throw e;
}
}
async queryMyFavorite(page, size) {
try {
const tools = await this.getTools();
const queryMyFavoriteCaps = tools.queryMyFavoriteCap;
if (!queryMyFavoriteCaps) {
throw new Error("queryMyFavoriteCaps tool not available on MCP server");
}
const result = await queryMyFavoriteCaps.execute(
{
page,
pageSize: size
},
{
toolCallId: "queryMyFavoriteCaps",
messages: []
}
);
if (result.isError) {
throw new Error(result.content?.[0]?.text || "Unknown error");
}
const queryResult = JSON.parse(result.content[0].text);
if (queryResult.code !== 200) {
throw new Error(`queryMyFavoriteCaps failed: ${queryResult.error || "Unknown error"}`);
}
return {
code: queryResult.code,
data: {
totalItems: queryResult.data.totalItems,
page: queryResult.data.page,
pageSize: queryResult.data.pageSize,
items: queryResult.data.items
}
};
} catch (e) {
throw e;
}
}
async queryCapStats(capId) {
try {
const tools = await this.getTools();
const queryCapStats = tools.queryCapStats;
if (!queryCapStats) {
throw new Error("queryCapStats tool not available on MCP server");
}
const result = await queryCapStats.execute(
{
capId
},
{
toolCallId: "queryCapStats",
messages: []
}
);
if (result.isError) {
throw new Error(result.content?.[0]?.text || "Unknown error");
}
const queryResult = JSON.parse(result.content[0].text);
if (queryResult.code !== 200) {
throw new Error(`query cap stats failed: ${queryResult.error || "Unknown error"}`);
}
return queryResult;
} catch (e) {
throw e;
}
}
async rateCap(capId, rating) {
if (rating < 1 || rating > 5 || !Number.isInteger(rating)) {
throw new Error("Rating must be an integer between 1 and 5");
}
try {
const tools = await this.getTools();
const rateCap = tools.rateCap;
if (!rateCap) {
throw new Error("rateCap tool not available on MCP server");
}
const result = await rateCap.execute(
{
capId,
rating
},
{
toolCallId: "rateCap",
messages: []
}
);
if (result.isError) {
throw new Error(result.content?.[0]?.text || "Unknown error");
}
return {
code: 200,
data: true
};
} catch (e) {
throw e;
}
}
async queryCapRatingDistribution(capId) {
try {
const tools = await this.getTools();
const queryCapRatingDistribution = tools.queryCapRatingDistribution;
if (!queryCapRatingDistribution) {
throw new Error("queryCapRatingDistribution tool not available on MCP server");
}
const result = await queryCapRatingDistribution.execute(
{
capId
},
{
toolCallId: "queryCapRatingDistribution",
messages: []
}
);
if (result.isError) {
throw new Error(result.content?.[0]?.text || "Unknown error");
}
const content = result.content?.[0]?.text;
if (content) {
try {
const resut = JSON.parse(content);
return {
code: 200,
data: resut.data.distribution
};
} catch (parseError) {
throw new Error("Failed to parse rating distribution response");
}
}
throw new Error("No data received");
} catch (e) {
throw e;
}
}
async install(capId, action) {
try {
const tools = await this.getTools();
const favoriteCap = tools.favoriteCap;
if (!favoriteCap) {
throw new Error("favoriteCap tool not available on MCP server");
}
const result = await favoriteCap.execute(
{
capId,
action: action === "isInstall" ? "isFavorite" : action
},
{
toolCallId: "favoriteCap",
messages: []
}
);
if (result.isError) {
throw new Error(result.content?.[0]?.text || "Unknown error");
}
if (action === "isInstall") {
const data = JSON.parse(result.content[0].text);
return {
code: 200,
data: data.isFavorite
};
} else {
return {
code: 200,
data: true
};
}
} catch (e) {
throw e;
}
}
async updateEnableCap(capId, action) {
try {
const tools = await this.getTools();
const updateEnableCap = tools.updateEnableCap;
if (!updateEnableCap) {
throw new Error("updateEnableCap tool not available on MCP server");
}
const result = await updateEnableCap.execute(
{
capId,
action
},
{
toolCallId: "updateEnableCap",
messages: []
}
);
if (result.isError) {
throw new Error(result.content?.[0]?.text || "Unknown error");
}
return {
code: 200,
data: true
};
} catch (e) {
throw e;
}
}
// async downloadByID(id: string, format?: "base64" | "utf8"): Promise<Cap> {
// const result = await this.queryByID({ id: id });
//
// if (result.code === 200) {
// return this.downloadByCID(result.data!.cid, format);
// } else {
// throw new Error("Invalid Cap ID");
// }
// }
async downloadByID(id) {
try {
const tools = await this.getTools();
const downloadCap = tools.downloadCap;
if (!downloadCap) {
throw new Error("downloadCap tool not available on MCP server");
}
const result = await downloadCap.execute(
{
id
},
{
toolCallId: "download-cap",
messages: []
}
);
if (result.isError) {
throw new Error(result.content?.[0]?.text || "Unknown error");
}
const downloadResult = JSON.parse(result.content[0].text);
if (downloadResult.code !== 200) {
throw new Error(`Download failed: ${downloadResult.error || "Unknown error"}`);
}
const data = downloadResult.data.rawData;
const utf8 = new TextDecoder().decode(Uint8Array.from(atob(data), (c) => c.charCodeAt(0)));
return yaml.load(utf8);
} catch (e) {
throw e;
}
}
// async registerCap(cap: Cap) {
// // len > 6 && len < 20, only contain a-z, A-Z, 0-9, _
// if (!/^[a-zA-Z0-9_]{6,20}$/.test(cap.idName)) {
// throw new Error(
// "Name must be between 6 and 20 characters and only contain a-z, A-Z, 0-9, _",
// );
// }
//
// // 1. Create ACP (Agent Capability Package) file
// const acpContent = yaml.dump(cap);
//
// // 2. Upload ACP file to IPFS using nuwa-cap-store MCP
// const cid = await this.uploadToIPFS(cap.id, acpContent);
//
// // 3. Call Move contract to register the capability
// const result = await this.registerOnChain(cap.idName, cid, this.env.keyManager);
//
// if (result.execution_info.status.type !== "executed") {
// throw new Error("unknown error");
// }
//
// return cid;
// }
async registerCap(cap) {
if (!/^[a-zA-Z0-9_]{6,20}$/.test(cap.idName)) {
throw new Error("Name must be between 6 and 20 characters and only contain a-z, A-Z, 0-9, _");
}
const acpContent = yaml.dump(cap);
const encoder = new TextEncoder();
const bytes = encoder.encode(acpContent);
const rawData = btoa(String.fromCharCode(...bytes));
const tools = await this.getTools();
const uploadCap = tools.uploadCap;
const result = await uploadCap.execute(
{
cap: rawData
},
{
toolCallId: "upload-cap",
messages: []
}
);
if (result.isError) {
throw new Error(result.content?.[0]?.text || "Unknown error");
}
const uploadResult = JSON.parse(result.content[0].text);
const uploadData = uploadResult.data;
if (uploadResult.code !== 200) {
throw new Error(`Upload cap failed: ${uploadResult.error || "Unknown error"}`);
}
return cap.id;
}
// private async uploadToIPFS(
// name: string,
// content: string,
// ): Promise<string> {
//
// try {
// // Get tools from MCP server
// const tools = await this.getTools()
// const uploadCap = tools.uploadCap;
//
// if (!uploadCap) {
// throw new Error("uploadCap tool not available on MCP server");
// }
//
// // Convert content to base64 (UTF-8 safe)
// const encoder = new TextEncoder();
// const bytes = encoder.encode(content);
// const fileData = btoa(String.fromCharCode(...bytes));
// const fileName = `${name}.cap.yaml`;
//
// // Upload file to IPFS
// const result = await uploadCap.execute(
// {
// fileName,
// fileData,
// },
// {
// toolCallId: "upload-cap",
// messages: [],
// },
// );
//
// if (result.isError) {
// throw new Error((result.content as any)?.[0]?.text || "Unknown error");
// }
//
// const uploadResult = JSON.parse((result.content as any)[0].text);
// const uploadData = uploadResult.data;
//
// if (uploadResult.code !== 200 || !uploadData.ipfsCid) {
// throw new Error(
// `Upload cap failed: ${uploadResult.error || "Unknown error"}`,
// );
// }
//
// return uploadData.ipfsCid;
// } catch (e) {
// throw e
// }
// }
//
// private async registerOnChain(
// name: string,
// cid: string,
// signer: SignerInterface,
// ) {
// const chainSigner = await DidAccountSigner.create(signer);
// const transaction = new Transaction();
// transaction.callFunction({
// target: `${this.contractAddress}::acp_registry::register`,
// typeArgs: [],
// args: [Args.string(name), Args.string(cid)],
// maxGas: 500000000,
// });
//
// return await this.roochClient.signAndExecuteTransaction({
// transaction,
// signer: chainSigner,
// });
// }
};
// src/restful.ts
var yaml2 = __toESM(require("js-yaml"), 1);
var CapKitRestful = class {
constructor(apiUrl) {
this.apiUrl = apiUrl;
}
async queryCap(capId) {
const response = await fetch(`${this.apiUrl}/cap/${capId}`);
return await response.json();
}
async queryCaps(name, tags, page, pageSize, sortBy, sortOrder) {
const params = new URLSearchParams();
if (name) params.append("name", name);
if (tags && tags.length > 0) {
tags.forEach((tag) => params.append("tags", tag));
}
if (page !== void 0) params.append("page", page.toString());
if (pageSize !== void 0) params.append("pageSize", pageSize.toString());
if (sortBy) params.append("sortBy", sortBy);
if (sortOrder) params.append("sortOrder", sortOrder);
const url = params.toString() ? `${this.apiUrl}/caps?${params.toString()}` : `${this.apiUrl}/caps`;
const response = await fetch(url);
return await response.json();
}
async queryUserInstalledCaps(did, page, pageSize) {
const params = new URLSearchParams();
if (did) params.append("did", did);
if (page !== void 0) params.append("page", page.toString());
if (pageSize !== void 0) params.append("pageSize", pageSize.toString());
const url = `${this.apiUrl}/caps/installed?${params.toString()}`;
const response = await fetch(url);
return await response.json();
}
async downloadCap(capId) {
const response = await fetch(`${this.apiUrl}/cap/download/${capId}`);
const result = await response.json();
const utf8 = new TextDecoder().decode(
Uint8Array.from(atob(result.data.raw_data), (c) => c.charCodeAt(0))
);
return yaml2.load(utf8);
}
async downloadCaps(capIDs) {
if (capIDs.length === 0) {
return {
successful: {},
failed: {},
summary: {
successful: 0,
failed: 0,
total: 0
}
};
}
const response = await fetch(`${this.apiUrl}/caps/download`, {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({ ids: capIDs })
});
const result = await response.json();
const successful = result.data.successful;
const formatSuccessful = {};
for (const [id, value] of Object.entries(successful)) {
const utf8 = new TextDecoder().decode(
Uint8Array.from(atob(value), (c) => c.charCodeAt(0))
);
const cap = yaml2.load(utf8);
formatSuccessful[id] = cap;
}
return {
...result.data,
successful: formatSuccessful
};
}
};
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
CapArtifactSchema,
CapAuthorDIDSchema,
CapCoreSchema,
CapIDNameSchema,
CapIDSchema,
CapKitMcp,
CapKitRestful,
CapMcpServerSchema,
CapMetadataSchema,
CapModelSchema,
CapPromptSchema,
CapPromptSuggestionSchema,
CapSchema,
CapStatsSchema,
CapThumbnailSchema,
RatingDistribution,
ResultCapMetadataSchema
});
//# sourceMappingURL=index.cjs.map