cline-sdk
Version:
Comprehensive SDK for Cline - AI-powered development assistant with database integration, execution modes, and custom functions
202 lines โข 6.89 kB
JavaScript
;
/**
* Function Registry - Register and manage custom functions for Cline
*
* This allows users to register their own JavaScript functions that can be
* called by the AI assistant like built-in tools or MCP server functions.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.FunctionRegistry = void 0;
class FunctionRegistry {
constructor() {
this.functions = new Map();
}
/**
* Register a new custom function
*/
register(definition, implementation) {
if (this.functions.has(definition.name)) {
throw new Error(`Function '${definition.name}' is already registered`);
}
// Validate function definition
this.validateDefinition(definition);
const registeredFunction = {
definition,
implementation,
metadata: {
registeredAt: new Date(),
callCount: 0,
},
};
this.functions.set(definition.name, registeredFunction);
console.log(`๐ง Registered custom function: ${definition.name}`);
}
/**
* Unregister a function
*/
unregister(name) {
const removed = this.functions.delete(name);
if (removed) {
console.log(`๐๏ธ Unregistered custom function: ${name}`);
}
return removed;
}
/**
* Call a registered function
*/
async call(name, args) {
const func = this.functions.get(name);
if (!func) {
throw new Error(`Function '${name}' is not registered`);
}
// Update metadata
func.metadata.callCount++;
func.metadata.lastCalled = new Date();
try {
console.log(`๐ Calling custom function: ${name}`);
console.log(`๐ฅ Args:`, args);
const result = await func.implementation(...args);
console.log(`๐ค Result:`, result);
return result;
}
catch (error) {
console.error(`โ Custom function '${name}' failed:`, error);
throw error;
}
}
/**
* Get a function definition by name
*/
getFunction(name) {
return this.functions.get(name);
}
/**
* Get all registered functions
*/
getAllFunctions() {
return Array.from(this.functions.values());
}
/**
* Get function names
*/
getFunctionNames() {
return Array.from(this.functions.keys());
}
/**
* Get functions by category
*/
getFunctionsByCategory(category) {
return this.getAllFunctions().filter((func) => func.definition.category === category);
}
/**
* Get function metadata/stats
*/
getStats() {
const functions = this.getAllFunctions();
const totalCalls = functions.reduce((sum, func) => sum + func.metadata.callCount, 0);
const categories = {};
functions.forEach((func) => {
const category = func.definition.category || "uncategorized";
categories[category] = (categories[category] || 0) + 1;
});
const mostUsed = functions.reduce((max, func) => {
return func.metadata.callCount > (max?.calls || 0)
? { name: func.definition.name, calls: func.metadata.callCount }
: max;
}, null);
return {
totalFunctions: functions.length,
totalCalls,
categories,
mostUsed,
};
}
/**
* Clear all registered functions
*/
clear() {
this.functions.clear();
console.log("๐งน Cleared all custom functions");
}
/**
* Validate function definition
*/
validateDefinition(definition) {
if (!definition.name || typeof definition.name !== "string") {
throw new Error("Function name is required and must be a string");
}
if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(definition.name)) {
throw new Error("Function name must be a valid identifier (letters, numbers, underscore)");
}
if (!definition.description || typeof definition.description !== "string") {
throw new Error("Function description is required and must be a string");
}
if (!Array.isArray(definition.parameters)) {
throw new Error("Function parameters must be an array");
}
// Validate each parameter
definition.parameters.forEach((param, index) => {
if (!param.name || typeof param.name !== "string") {
throw new Error(`Parameter ${index} name is required and must be a string`);
}
if (!param.type || !["string", "number", "boolean", "object", "array"].includes(param.type)) {
throw new Error(`Parameter ${param.name} type must be one of: string, number, boolean, object, array`);
}
if (!param.description || typeof param.description !== "string") {
throw new Error(`Parameter ${param.name} description is required and must be a string`);
}
});
}
/**
* Convert to tool definition format for AI
*/
getToolDefinitions() {
return this.getAllFunctions().map((func) => ({
name: func.definition.name,
description: func.definition.description,
inputSchema: this.parametersToSchema(func.definition.parameters),
}));
}
/**
* Convert parameters to JSON schema format
*/
parametersToSchema(parameters) {
const properties = {};
const required = [];
parameters.forEach((param) => {
if (param.required !== false) {
required.push(param.name);
}
let property = {
type: param.type,
description: param.description,
};
if (param.enum) {
property.enum = param.enum;
}
if (param.type === "object" && param.properties) {
property.properties = {};
Object.entries(param.properties).forEach(([key, subParam]) => {
property.properties[key] = {
type: subParam.type,
description: subParam.description,
};
});
}
if (param.type === "array" && param.items) {
property.items = {
type: param.items.type,
description: param.items.description,
};
}
properties[param.name] = property;
});
return {
type: "object",
properties,
required,
};
}
}
exports.FunctionRegistry = FunctionRegistry;
//# sourceMappingURL=function-registry.js.map