diff --git a/packages/kbot/dist-in/ai-tools/constants.d.ts b/packages/kbot/dist-in/ai-tools/constants.d.ts new file mode 100644 index 00000000..13df1c76 --- /dev/null +++ b/packages/kbot/dist-in/ai-tools/constants.d.ts @@ -0,0 +1,2 @@ +export declare const LOGGER_NAME = "llm-tools-cli"; +export declare const EXCLUDE_GLOB: string[]; diff --git a/packages/kbot/dist-in/ai-tools/constants.js b/packages/kbot/dist-in/ai-tools/constants.js new file mode 100644 index 00000000..bfaf659a --- /dev/null +++ b/packages/kbot/dist-in/ai-tools/constants.js @@ -0,0 +1,11 @@ +export const LOGGER_NAME = 'llm-tools-cli'; +export const EXCLUDE_GLOB = [ + "**/node_modules/**", + "**/dist/**", + "**/build/**", + "**/coverage/**", + "*.log", + ".kbot", + ".git" +]; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uc3RhbnRzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2FpLXRvb2xzL2NvbnN0YW50cy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxNQUFNLENBQUMsTUFBTSxXQUFXLEdBQUcsZUFBZSxDQUFBO0FBRTFDLE1BQU0sQ0FBQyxNQUFNLFlBQVksR0FBRztJQUN4QixvQkFBb0I7SUFDcEIsWUFBWTtJQUNaLGFBQWE7SUFDYixnQkFBZ0I7SUFDaEIsT0FBTztJQUNQLE9BQU87SUFDUCxNQUFNO0NBQ1QsQ0FBQSJ9 \ No newline at end of file diff --git a/packages/kbot/dist-in/ai-tools/index.d.ts b/packages/kbot/dist-in/ai-tools/index.d.ts new file mode 100644 index 00000000..49bbe7cf --- /dev/null +++ b/packages/kbot/dist-in/ai-tools/index.d.ts @@ -0,0 +1,38 @@ +import { z } from 'zod'; +import { ISettingsParam, Logger } from "tslog"; +import * as winston from 'winston'; +import { IKBotTask } from './types.js'; +export declare let logger: Logger; +export declare const TLogLevelNameSchema: z.ZodEnum<{ + silly: "silly"; + trace: "trace"; + debug: "debug"; + info: "info"; + warn: "warn"; + error: "error"; + fatal: "fatal"; +}>; +export type LogLevel = z.infer; +export declare enum LogLevelEx { + silly = 0, + trace = 1, + debug = 2, + info = 3, + warn = 4, + error = 5, + fatal = 6 +} +export declare enum ELogTargets { + Console = 1, + FileText = 2, + FileJson = 4, + Seq = 8 +} +export declare function createLogger(name: string, options?: ISettingsParam): Logger; +export declare const defaultLogger: Logger; +export declare const winstonLogger: (name: string, file: string, targets?: ELogTargets) => winston.Logger; +export declare const createFileLogger: (logger: Logger, level: number, file: string) => Logger; +export declare const toolLoggerTS: (name: any, options: IKBotTask) => Logger; +export declare const toolLogger: (name: any, options?: IKBotTask) => winston.Logger; +export * from './types.js'; +export * from './types_kbot.js'; diff --git a/packages/kbot/dist-in/ai-tools/index.js b/packages/kbot/dist-in/ai-tools/index.js new file mode 100644 index 00000000..d5cb261f --- /dev/null +++ b/packages/kbot/dist-in/ai-tools/index.js @@ -0,0 +1,163 @@ +import * as path from 'path'; +import { z } from 'zod'; +import { Logger } from "tslog"; +import * as winston from 'winston'; +import TransportStream from 'winston-transport'; +import { SeqTransport } from '@datalust/winston-seq'; +import { createStream } from "rotating-file-stream"; +import { CONFIG_DEFAULT } from '@polymech/commons'; +import { sync as read } from '@polymech/fs/read'; +import { sync as write } from '@polymech/fs/write'; +import { sync as exists } from '@polymech/fs/exists'; +export let logger = createLogger('osr-ai-tools'); +export const TLogLevelNameSchema = z.enum(["silly", "trace", "debug", "info", "warn", "error", "fatal"]); +export var LogLevelEx; +(function (LogLevelEx) { + LogLevelEx[LogLevelEx["silly"] = 0] = "silly"; + LogLevelEx[LogLevelEx["trace"] = 1] = "trace"; + LogLevelEx[LogLevelEx["debug"] = 2] = "debug"; + LogLevelEx[LogLevelEx["info"] = 3] = "info"; + LogLevelEx[LogLevelEx["warn"] = 4] = "warn"; + LogLevelEx[LogLevelEx["error"] = 5] = "error"; + LogLevelEx[LogLevelEx["fatal"] = 6] = "fatal"; +})(LogLevelEx || (LogLevelEx = {})); +export var ELogTargets; +(function (ELogTargets) { + ELogTargets[ELogTargets["Console"] = 1] = "Console"; + ELogTargets[ELogTargets["FileText"] = 2] = "FileText"; + ELogTargets[ELogTargets["FileJson"] = 4] = "FileJson"; + ELogTargets[ELogTargets["Seq"] = 8] = "Seq"; +})(ELogTargets || (ELogTargets = {})); +export function createLogger(name, options) { + return new Logger({ + name, + type: 'pretty', + ...options, + }); +} +export const defaultLogger = createLogger('DefaultLogger', { + minLevel: LogLevelEx.info +}); +class JsonArrayFileTransport extends TransportStream { + filename; + constructor(opts) { + super(opts); + opts.filename = opts.filename; + this.filename = opts.filename || 'logs.json'; + setImmediate(() => this.emit('opened')); + } + log(info, next) { + setImmediate(() => this.emit('logged', info)); + const { level, message, exception, stack, ...props } = info; + const fileExists = exists(this.filename); + const existingLogs = fileExists + ? read(this.filename, 'json') + : []; + const entry = { + level: info.level, + message: info.message, + timestamp: new Date().toISOString(), + ...info + }; + existingLogs.push(entry); + write(this.filename, existingLogs); + next(); + } + close() { + setImmediate(() => this.emit('closed')); + } + flush() { + return new Promise((resolve, reject) => { + resolve(true); + }); + } +} +class TSLogTransport extends TransportStream { + constructor(opts) { + super(opts); + setImmediate(() => this.emit('opened')); + } + log(info, next) { + setImmediate(() => this.emit('logged', info)); + const { level, message, exception, stack, ...props } = info; + defaultLogger.info(info); + next(); + } +} +export const winstonLogger = (name, file, targets = ELogTargets.Console | ELogTargets.FileJson) => { + const logger = winston.createLogger({ + defaultMeta: { service: name }, + level: 'debug', + transports: [] + }); + if (targets & ELogTargets.Console) { + //logger.add(new TSLogTransport({})) + logger.add(new winston.transports.Console({ + format: winston.format.combine(winston.format.timestamp({ format: 'MM/DD/YYYY hh:mm:ss.SSS' }), + ///winston.format.json(), + winston.format.colorize(), winston.format.printf(info => { + let message = null; + try { + message = JSON.stringify(info.message); + } + catch (e) { + } + return `[${info.level}] [${name}] | message: ${message.substring(0, 200)}`; + })) + })); + } + if (targets & ELogTargets.FileText) { + logger.add(new winston.transports.File({ + format: winston.format.combine(winston.format.timestamp(), winston.format.timestamp({ format: 'MM/DD/YYYY hh:mm:ss.SSS' }), winston.format.json(), winston.format.printf(info => { + return JSON.stringify(info, null, 2); + })), + dirname: path.parse(file).dir, + filename: path.parse(file).base + })); + } + if (targets & ELogTargets.FileJson) { + logger.add(new JsonArrayFileTransport({ + filename: file + })); + } + if (targets & ELogTargets.Seq) { + const config = CONFIG_DEFAULT(); + if (config.seq) { + logger.add(new SeqTransport({ + ...config.seq, + onError: (e => { }) + })); + } + } + return logger; +}; +export const createFileLogger = (logger, level, file) => { + const rfs = createStream(file, { + size: "10M", // rotate every 10 MegaBytes written + interval: "1d", // rotate daily + compress: "gzip", // compress rotated files + }); + const log = new Logger({ + type: "json", + attachedTransports: [ + (logObj) => { + rfs.write(JSON.stringify(logObj) + "\n"); + }, + ], + }); + return log; +}; +export const toolLoggerTS = (name, options) => { + let log = createLogger(name); + //log.settings.minLevel = options.logLevel + log = createFileLogger(log, options.logLevel, path.join(options.logs, `tools-${name}.json`)); + return log; +}; +export const toolLogger = (name, options = { logs: process.cwd() }) => { + const logPath = path.resolve(path.join(options.logs || './', `tools-${name}.json`)); + const log = winstonLogger(name, logPath, ELogTargets.Console); + return log; +}; +export * from './types.js'; +export * from './types_kbot.js'; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvYWktdG9vbHMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLElBQUksTUFBTSxNQUFNLENBQUE7QUFDNUIsT0FBTyxFQUFFLENBQUMsRUFBRSxNQUFNLEtBQUssQ0FBQTtBQUV2QixPQUFPLEVBQWtCLE1BQU0sRUFBRSxNQUFNLE9BQU8sQ0FBQTtBQUU5QyxPQUFPLEtBQUssT0FBTyxNQUFNLFNBQVMsQ0FBQTtBQUNsQyxPQUFPLGVBQWUsTUFBTSxtQkFBbUIsQ0FBQTtBQUMvQyxPQUFPLEVBQUUsWUFBWSxFQUFDLE1BQU0sdUJBQXVCLENBQUE7QUFDbkQsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLHNCQUFzQixDQUFBO0FBRW5ELE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQTtBQUNsRCxPQUFPLEVBQUUsSUFBSSxJQUFJLElBQUksRUFBRSxNQUFNLG1CQUFtQixDQUFBO0FBQ2hELE9BQU8sRUFBRSxJQUFJLElBQUksS0FBSyxFQUFFLE1BQU0sb0JBQW9CLENBQUE7QUFDbEQsT0FBTyxFQUFFLElBQUksSUFBSSxNQUFNLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQTtBQUlwRCxNQUFNLENBQUMsSUFBSSxNQUFNLEdBQW9CLFlBQVksQ0FBQyxjQUFjLENBQUMsQ0FBQTtBQUNqRSxNQUFNLENBQUMsTUFBTSxtQkFBbUIsR0FBRyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsT0FBTyxFQUFFLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sRUFBRSxPQUFPLEVBQUUsT0FBTyxDQUFDLENBQUMsQ0FBQTtBQUV4RyxNQUFNLENBQU4sSUFBWSxVQVFYO0FBUkQsV0FBWSxVQUFVO0lBQ2xCLDZDQUFLLENBQUE7SUFDTCw2Q0FBSyxDQUFBO0lBQ0wsNkNBQUssQ0FBQTtJQUNMLDJDQUFJLENBQUE7SUFDSiwyQ0FBSSxD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 \ No newline at end of file diff --git a/packages/kbot/dist-in/ai-tools/lib/tools/fs.d.ts b/packages/kbot/dist-in/ai-tools/lib/tools/fs.d.ts new file mode 100644 index 00000000..d62651fa --- /dev/null +++ b/packages/kbot/dist-in/ai-tools/lib/tools/fs.d.ts @@ -0,0 +1,3 @@ +import { IKBotTask } from '../../types.js'; +export declare const decode_base64: (base64: string) => string; +export declare const tools: (target: string, options: IKBotTask) => Array; diff --git a/packages/kbot/dist-in/ai-tools/lib/tools/fs.js b/packages/kbot/dist-in/ai-tools/lib/tools/fs.js new file mode 100644 index 00000000..9e6eee58 --- /dev/null +++ b/packages/kbot/dist-in/ai-tools/lib/tools/fs.js @@ -0,0 +1,432 @@ +import * as path from 'path'; +import { sync as rm } from '@polymech/fs/remove'; +import { isString } from '@polymech/core/primitives'; +import { sync as write } from '@polymech/fs/write'; +import { sync as read } from '@polymech/fs/read'; +import { sync as rename } from '@polymech/fs/rename'; +import { sync as exists } from '@polymech/fs/exists'; +import { sanitize } from "@polymech/fs/utils"; +import { filesEx } from '@polymech/commons'; +import { toolLogger } from '../../index.js'; +import { EXCLUDE_GLOB } from '../../constants.js'; +import { glob } from 'glob'; +const isBase64 = (str) => { + // 1. Quick checks for length & allowed characters: + // - Must be multiple of 4 in length + // - Must match Base64 charset (A-Z, a-z, 0-9, +, /) plus optional "=" padding + if (!str || str.length % 4 !== 0) { + return false; + } + const base64Regex = /^[A-Za-z0-9+/]+={0,2}$/; + if (!base64Regex.test(str)) { + return false; + } + // 2. Attempt decode–re-encode to confirm validity: + try { + const decoded = atob(str); // Decode from Base64 + const reencoded = btoa(decoded); // Re-encode to Base64 + // Compare the re-encoded string to original + return reencoded === str; + } + catch { + return false; + } +}; +export const decode_base64 = (base64) => { + try { + if (!isBase64(base64)) { + return base64; + } + return Buffer.from(base64, 'base64').toString('utf-8'); + } + catch (error) { + throw new Error('Failed to decode base64 string'); + } +}; +// Helper function for smart Base64 decoding +const decodeContentSmart = (content, logger, identifier) => { + if (!content || typeof content !== 'string') { + return content; // Return original content if null, undefined, or not a string + } + const lines = content.split(/\r?\n/); + const processedLines = lines.map(line => { + const trimmedLine = line.trim(); + if (!trimmedLine) { + return ''; // Preserve empty lines between potential blocks but decode the blocks themselves + } + try { + // Attempt to decode Base64 + const decodedLine = Buffer.from(trimmedLine, 'base64').toString('utf-8'); + // Validate if it was actually Base64 by re-encoding + const reEncodedLine = Buffer.from(decodedLine, 'utf-8').toString('base64'); + // Revised Validation Check: + // Compare original trimmed line with re-encoded line. + // Allow for potential padding differences by checking both exact match and no-pad match. + const originalNoPad = trimmedLine.replace(/={1,2}$/, ''); + const reEncodedNoPad = reEncodedLine.replace(/={1,2}$/, ''); + if (reEncodedLine === trimmedLine || reEncodedNoPad === originalNoPad) { + logger.debug(`Successfully decoded Base64 line for ${identifier}`); + return decodedLine; + } + // If validation fails, treat as plain text + logger.debug(`Re-encoding mismatch for ${identifier}. Original: '${trimmedLine}', Re-encoded: '${reEncodedLine}', using original trimmed line.`); + return trimmedLine; + } + catch (decodeError) { + // If decoding throws an error, assume it's plain text + // Use debug level as this is expected for non-base64 lines + logger.debug(`Base64 decoding failed for line in ${identifier}, assuming plain text. Line: ${trimmedLine}`); + return trimmedLine; // Return original trimmed line + } + }); + // Join the processed lines back together + return processedLines.join('\n'); +}; +export const tools = (target, options) => { + const logger = toolLogger('fs', options); + return [ + { + type: 'function', + function: { + name: 'list_files', + description: 'List all files in a directory', + parameters: { + type: 'object', + properties: { + directory: { type: 'string' }, + pattern: { type: 'string', optional: true } + }, + required: ['directory'] + }, + function: async (params) => { + try { + const directory = path.join(target, sanitize(params.directory)); + if (!exists(directory)) { + logger.debug(`Tool::ListFiles Directory ${directory} does not exist`); + return []; + } + let pattern = params.pattern || '**/*'; + logger.debug(`Tool::ListFiles Listing files in ${directory} with pattern ${pattern}`); + pattern = [ + ...EXCLUDE_GLOB, + pattern + ]; + const ret = await glob(pattern, { + cwd: directory, + absolute: false, + ignore: EXCLUDE_GLOB + }); + return ret; + } + catch (error) { + logger.error('Error listing files', error); + throw error; + } + }, + parse: JSON.parse + } + }, + { + type: 'function', + function: { + name: 'read_files', + description: 'Reads files in a directory with a given pattern', + parameters: { + type: 'object', + properties: { + directory: { type: 'string' }, + pattern: { type: 'string', optional: true } + }, + required: ['directory'] + }, + function: async (params) => { + try { + const pattern = params.pattern || '**/*'; + let entries = filesEx(target, pattern); + let ret = entries.map((entry) => { + try { + let content = read(entry); + return { + path: path.relative(target, entry).replace(/\\/g, '/'), + content: content.toString() + }; + } + catch (error) { + logger.error(`Error reading file ${entry}:`, error); + return null; + } + }); + ret = ret.filter((entry) => (entry !== null && entry.content)); + logger.debug(`Tool::ReadFiles Reading files in ${target} with pattern ${pattern} : ${ret.length} files`, ret.map((entry) => entry.path)); + return ret; + } + catch (error) { + logger.error('Error listing files', error); + throw error; + } + }, + parse: JSON.parse + } + }, + { + type: 'function', + function: { + name: 'remove_file', + description: 'Remove a file at given path', + parameters: { + type: 'object', + properties: { + path: { type: 'string' } + }, + required: ['path'] + }, + function: async (params) => { + try { + const filePath = path.join(target, sanitize(params.path)); + logger.debug(`Tool::RemoveFile Removing file ${filePath}`); + rm(filePath); + return true; + } + catch (error) { + logger.error('Error removing file', error); + throw error; + } + }, + parse: JSON.parse + } + }, + { + type: 'function', + function: { + name: 'rename_file', + description: 'Rename or move a file or directory', + parameters: { + type: 'object', + properties: { + src: { type: 'string' }, + dst: { type: 'string' } + }, + required: ['path'] + }, + function: async (params) => { + try { + const src = path.join(target, sanitize(params.src)); + const dst = path.join(target, sanitize(params.dst)); + logger.debug(`Tool::Rename file ${src} to ${dst}`); + rename(src, dst); + rm(src); + return true; + } + catch (error) { + logger.error('Error removing file', error); + throw error; + } + }, + parse: JSON.parse + } + }, + { + type: 'function', + function: { + name: "modify_project_files", + description: "Create or modify existing project files in one shot, preferably used for creating project structure)", + parameters: { + type: "object", + properties: { + files: { + type: "array", + items: { + type: "object", + properties: { + path: { type: "string" }, + content: { type: "string", description: "new file content (Part of JSON payload)" } + }, + required: ["path", "content"] + } + } + }, + required: ["files"], + }, + function: async (ret) => { + try { + if (!target) { + logger.error(`Tool::FS:modify_project_files : Root path required`); + return; + } + let { files } = ret; + if (isString(files)) { + try { + files = JSON.parse(files); + } + catch (error) { + logger.error(`Tool::modify_project_files : Structure Error parsing files`, error, ret); + // Consider writing the raw input for debugging if JSON parsing fails + // write(path.join(target, 'tools-output-error.json'), files) + return error.message; + } + } + for (const file of files) { + const sanitizedPath = sanitize(file.path); + const filePath = path.join(target, sanitizedPath); + logger.debug(`Tool:modify_project_files writing file ${filePath}`); + try { + // const contentToWrite = decodeContentSmart(file.content, logger, sanitizedPath); + try { + await write(filePath, file.content); + } + catch (writeError) { + logger.error(`Tool:modify_project_files Error writing file ${filePath}`, writeError); + } + } + catch (error) { + logger.error(`Tool:modify_project_files Error processing file content for ${filePath}`, error); + } + } + } + catch (error) { + logger.error(`Error creating project structure`, error); + } + }, + parse: JSON.parse, + }, + }, + { + type: 'function', + function: { + name: "write_file", + description: "Writes to a file, given a path and content (Part of JSON payload). No directory or file exists check needed!", + parameters: { + type: "object", + properties: { + file: { + type: "object", + properties: { + path: { type: "string" }, + content: { type: "string", description: "new file content (Part of JSON payload)" } + } + } + }, + required: ["file"], + }, + function: async (params) => { + let fileInfo; + try { + if (isString(params)) { + try { + params = JSON.parse(params); + } + catch (error) { + logger.error(`Tool::write_file : Structure Error parsing JSON`, error, params); + return error.message; + } + } + fileInfo = params.file; // Keep fileInfo accessible + if (!target || !fileInfo || !fileInfo.path || typeof fileInfo.content === 'undefined') { + logger.error(`Tool::write_file : Path/Target/Content are required`, fileInfo); + return false; // Indicate failure + } + const sanitizedPath = sanitize(fileInfo.path); + const filePath = path.join(target, sanitizedPath); + logger.debug(`Tool::write_file Writing file ${filePath}`); + try { + // Use the smart decoding helper function + // const contentToWrite = decodeContentSmart(fileInfo.content, logger, sanitizedPath); + await write(filePath, fileInfo.content); + return true; + } + catch (error) { + // Log error related to processing or writing the file + logger.error(`Tool:write_file Error processing or writing file ${sanitizedPath}`, error); + return false; // Indicate failure + } + } + catch (error) { + logger.error(`Tool:write_file Error writing file ${fileInfo?.path ? sanitize(fileInfo.path) : 'unknown'}`, error); + return false; // Indicate failure + } + }, + parse: JSON.parse, + }, + }, + { + type: 'function', + function: { + name: "file_exists", + description: "check if a file or folder exists", + parameters: { + type: "object", + properties: { + file: { + type: "object", + properties: { + path: { type: "string" } + } + } + }, + required: ["file"], + }, + function: async (ret) => { + try { + if (isString(ret)) { + try { + ret = JSON.parse(ret); + } + catch (error) { + logger.error(`Tool::file_exists : Structure Error parsing files`, error, ret); + return error.message; + } + } + const { file } = ret; + if (!target || !file.path) { + logger.error(`Tool::file_exists : Path is required`, ret); + return; + } + const sanitizedPath = sanitize(file.path); + const filePath = path.join(target, sanitizedPath); + const res = exists(filePath); + logger.debug(`Tool::file_exists ${filePath} exists: ${res}`); + return res ? true : false; + } + catch (error) { + logger.error(`Tool:file_exists error`, error); + return false; + } + }, + parse: JSON.parse, + }, + }, + { + type: 'function', + function: { + name: "read_file", + description: "read a file, at given a path", + parameters: { + type: "object", + properties: { + file: { + type: "object", + properties: { + path: { type: "string" } + } + } + }, + required: ["file"], + }, + function: async (ret) => { + try { + const { file } = ret; + const sanitizedPath = sanitize(file.path); + const filePath = path.join(target, sanitizedPath); + logger.debug(`Tool::ReadFile Reading file ${filePath}`); + return read(filePath, 'string'); + } + catch (error) { + logger.error(`Error reading file`, error); + } + }, + parse: JSON.parse + } + } + ]; +}; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZnMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvYWktdG9vbHMvbGliL3Rvb2xzL2ZzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxJQUFJLE1BQU0sTUFBTSxDQUFBO0FBRTVCLE9BQU8sRUFBRSxJQUFJLElBQUksRUFBRSxFQUFFLE1BQU0scUJBQXFCLENBQUE7QUFDaEQsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLDJCQUEyQixDQUFBO0FBQ3BELE9BQU8sRUFBRSxJQUFJLElBQUksS0FBSyxFQUFFLE1BQU0sb0JBQW9CLENBQUE7QUFDbEQsT0FBTyxFQUFFLElBQUksSUFBSSxJQUFJLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQTtBQUNoRCxPQUFPLEVBQUUsSUFBSSxJQUFJLE1BQU0sRUFBRSxNQUFNLHFCQUFxQixDQUFBO0FBQ3BELE9BQU8sRUFBRSxJQUFJLElBQUksTUFBTSxFQUFFLE1BQU0scUJBQXFCLENBQUE7QUFDcEQsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLG9CQUFvQixDQUFBO0FBQzdDLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQTtBQUUzQyxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sZ0JBQWdCLENBQUE7QUFFM0MsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLG9CQUFvQixDQUFBO0FBRWpELE9BQU8sRUFBRSxJQUFJLEVBQUUsTUFBTSxNQUFNLENBQUE7QUFFM0IsTUFBTSxRQUFRLEdBQUcsQ0FBQyxHQUFXLEVBQVcsRUFBRTtJQUN0QyxtREFBbUQ7SUFDbkQsdUNBQXVDO0lBQ3ZDLGlGQUFpRjtJQUNqRixJQUFJLENBQUMsR0FBRyxJQUFJLEdBQUcsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO1FBQ2pDLE9BQU8sS0FBSyxDQUFDO0lBQ2YsQ0FBQztJQUVELE1BQU0sV0FBVyxHQUFHLHdCQUF3QixDQUFDO0lBQzdDLElB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 \ No newline at end of file diff --git a/packages/kbot/dist-in/ai-tools/lib/tools/git.d.ts b/packages/kbot/dist-in/ai-tools/lib/tools/git.d.ts new file mode 100644 index 00000000..081be802 --- /dev/null +++ b/packages/kbot/dist-in/ai-tools/lib/tools/git.d.ts @@ -0,0 +1,2 @@ +import { IKBotTask } from '../../types.js'; +export declare const tools: (target: string, options: IKBotTask) => Array; diff --git a/packages/kbot/dist-in/ai-tools/lib/tools/git.js b/packages/kbot/dist-in/ai-tools/lib/tools/git.js new file mode 100644 index 00000000..34554f58 --- /dev/null +++ b/packages/kbot/dist-in/ai-tools/lib/tools/git.js @@ -0,0 +1,156 @@ +import * as path from 'path'; +import { simpleGit } from 'simple-git'; +import { sync as exists } from '@polymech/fs/exists'; +import { substitute } from '@polymech/commons'; +import { logger } from '../../index.js'; +import { toolLogger } from '../../index.js'; +import { findUpSync } from 'find-up'; +const commitFiles = async (filePaths, commitMessage, targetDirectory, variables = {}) => { + try { + if (!filePaths || !filePaths.length) { + logger.warn(`No files to commit`); + return; + } + if (!exists(path.join(targetDirectory, '.git'))) { + try { + logger.info(`Initializing repository at ${targetDirectory}`); + await initRepository(targetDirectory); + } + catch (e) { + logger.error(`Error initializing repository at ${targetDirectory} `, e.message, filePaths); + } + } + const git = simpleGit(targetDirectory); + try { + await git.add(filePaths); + } + catch (e) { + logger.error('Error adding files:', e.message, filePaths); + } + await git.commit(commitMessage); + try { + await git.raw(['branch', '-M', 'master']); + const repo = substitute(false, "${GIT_REPO}/${GIT_USER}/${REPO_NAME}.git", { + REPO_NAME: path.basename(targetDirectory), + ...variables + }); + await git.raw(['remote', 'add', 'origin', repo]); + await git.push(['--set-upstream', 'origin', 'master']); + return true; + } + catch (e) { + if (e.message.includes('remote origin already exists')) { + await git.push(['--set-upstream', 'origin', 'master']); + } + else { + logger.error('Tools::GIT : Error pushing files:', e.message, filePaths); + } + } + } + catch (error) { + logger.error('Error committing files:', error.message, filePaths); + throw error; + } +}; +const initRepository = async (targetDirectory, variables = {}) => { + try { + const git = simpleGit(targetDirectory); + if (!exists(path.join(targetDirectory, '.git'))) { + await git.init(); + logger.info('Git repository initialized successfully!'); + return true; + } + logger.info('Git repository already exists'); + return false; + } + catch (error) { + logger.error('Error initializing git repository:', error.message); + return false; + } +}; +export const tools = (target, options) => { + const logger = toolLogger('git', options); + if (!target) { + logger.warn(`Tools:GIT : Target is required`); + return []; + } + if (!exists(target)) { + logger.warn(`Tools:GIT : Project path doesnt exists ${target}`); + return []; + } + return [ + { + type: 'function', + function: { + name: "init_repository", + description: "Initialize a new git repository", + parameters: { + type: "object", + properties: {}, + required: [] + }, + function: async (params) => { + logger.info(`Tool::init_repository Init Repository in ${target}`); + const gitDir = findUpSync('.git', { type: 'directory', cwd: target }); + if (gitDir && exists(gitDir)) { + logger.info(`Repository already exists at ${gitDir}`); + return true; + } + try { + const ret = await initRepository(target, options.variables); + return true; + } + catch (error) { + logger.error(`Error initializing repository`, error); + return false; + } + }, + parse: JSON.parse, + } + }, + { + type: 'function', + function: { + name: "commit_files_git", + description: "Commit files using git", + parameters: { + type: "object", + properties: { + files: { + type: "array", + items: { + type: "string" + } + }, + message: { + type: "string" + } + }, + required: ["files"], + }, + function: async (ret) => { + debugger; + try { + const { files, message } = ret; + logger.info(`Tool::GIT Commit files ${files} in ${target}`); + if (!target) { + logger.error(`Tool::Git Commit : Target is required`); + return; + } + if (!exists(target)) { + logger.error(`Project doesnt path exists ${target}`); + return; + } + await commitFiles(files, message, target, options.variables); + } + catch (error) { + logger.error(`Error committing dependencies : ${error.message}`); + } + return true; + }, + parse: JSON.parse, + }, + } + ]; +}; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2l0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2FpLXRvb2xzL2xpYi90b29scy9naXQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLElBQUksTUFBTSxNQUFNLENBQUE7QUFHNUIsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFPLFlBQVksQ0FBQTtBQUV2QyxPQUFPLEVBQUUsSUFBSSxJQUFJLE1BQU0sRUFBRSxNQUFNLHFCQUFxQixDQUFBO0FBQ3BELE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQTtBQUU5QyxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sZ0JBQWdCLENBQUE7QUFDdkMsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGdCQUFnQixDQUFBO0FBRzNDLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxTQUFTLENBQUE7QUFFcEMsTUFBTSxXQUFXLEdBQUcsS0FBSyxFQUFFLFNBQW1CLEVBQUUsYUFBcUIsRUFBRSxlQUF1QixFQUFFLFlBQW9DLEVBQUUsRUFBRSxFQUFFO0lBQ3RJLElBQUksQ0FBQztRQUNELElBQUksQ0FBQyxTQUFTLElBQUksQ0FBQyxTQUFTLENBQUMsTUFBTSxFQUFFLENBQUM7WUFDbEMsTUFBTSxDQUFDLElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxDQUFBO1lBQ2pDLE9BQU07UUFDVixDQUFDO1FBQ0QsSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLGVBQWUsRUFBRSxNQUFNLENBQUMsQ0FBQyxFQUFFLENBQUM7WUFDOUMsSUFBSSxDQUFDO2dCQUNELE1BQU0sQ0FBQyxJQUFJLENBQUMsOEJBQThCLGVBQWUsRUFBRSxDQUFDLENBQUE7Z0JBQzVELE1BQU0sY0FBYyxDQUFDLGVBQWUsQ0FBQyxDQUFBO1lBQ3pDLENBQUM7WUFBQyxPQUFPLENBQU0sRUFBRSxDQUFDO2dCQUNkLE1BQU0sQ0FBQyxLQUFLLENBQUMsb0NBQW9DLGVB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 \ No newline at end of file diff --git a/packages/kbot/dist-in/ai-tools/lib/tools/interact.d.ts b/packages/kbot/dist-in/ai-tools/lib/tools/interact.d.ts new file mode 100644 index 00000000..081be802 --- /dev/null +++ b/packages/kbot/dist-in/ai-tools/lib/tools/interact.d.ts @@ -0,0 +1,2 @@ +import { IKBotTask } from '../../types.js'; +export declare const tools: (target: string, options: IKBotTask) => Array; diff --git a/packages/kbot/dist-in/ai-tools/lib/tools/interact.js b/packages/kbot/dist-in/ai-tools/lib/tools/interact.js new file mode 100644 index 00000000..7668bc96 --- /dev/null +++ b/packages/kbot/dist-in/ai-tools/lib/tools/interact.js @@ -0,0 +1,85 @@ +import { toolLogger } from '../../index.js'; +import { input, select } from '@inquirer/prompts'; +export const tools = (target, options) => { + const logger = toolLogger('interact', options); + return [ + { + type: 'function', + function: { + name: 'ask_question', + description: 'Ask user a simple question and get response', + parameters: { + type: 'object', + properties: { + question: { + type: 'string', + description: 'Question to ask the user' + }, + default: { + type: 'string', + description: 'Default answer', + optional: true + } + }, + required: ['question'] + }, + function: async (params) => { + try { + const answer = await input({ + message: params.question, + default: params.default + }); + return { response: answer }; + } + catch (error) { + logger.error('Error asking question:', error.message); + return null; + } + }, + parse: JSON.parse + } + }, + { + type: 'function', + function: { + name: 'choose_option', + description: 'Ask user to choose from multiple options', + parameters: { + type: 'object', + properties: { + message: { + type: 'string', + description: 'Message to show the user' + }, + choices: { + type: 'array', + items: { type: 'string' }, + description: 'List of choices' + }, + multiple: { + type: 'boolean', + description: 'Allow multiple selections', + optional: true + } + }, + required: ['message', 'choices'] + }, + function: async (params) => { + try { + const answer = await select({ + message: params.message, + choices: params.choices + }); + return { response: answer }; + } + catch (error) { + logger.error('Error in choice selection:', error.message); + return null; + } + }, + parse: JSON.parse + } + } + ]; +}; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW50ZXJhY3QuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvYWktdG9vbHMvbGliL3Rvb2xzL2ludGVyYWN0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUVBLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQTtBQUUzQyxPQUFPLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBRSxNQUFNLG1CQUFtQixDQUFBO0FBQ2pELE1BQU0sQ0FBQyxNQUFNLEtBQUssR0FBRyxDQUFDLE1BQWMsRUFBRSxPQUFrQixFQUFjLEVBQUU7SUFDcEUsTUFBTSxNQUFNLEdBQUcsVUFBVSxDQUFDLFVBQVUsRUFBRSxPQUFPLENBQUMsQ0FBQTtJQUM5QyxPQUFPO1FBQ0g7WUFDSSxJQUFJLEVBQUUsVUFBVTtZQUNoQixRQUFRLEVBQUU7Z0JBQ04sSUFBSSxFQUFFLGNBQWM7Z0JBQ3BCLFdBQVcsRUFBRSw2Q0FBNkM7Z0JBQzFELFVBQVUsRUFBRTtvQkFDUixJQUFJLEVBQUUsUUFBUTtvQkFDZCxVQUFVLEVBQUU7d0JBQ1IsUUFBUSxFQUFFOzRCQUNOLElBQUksRUFBRSxRQUFROzRCQUNkLFdBQVcsRUFBRSwwQkFBMEI7eUJBQzFDO3dCQUNELE9BQU8sRUFBRTs0QkFDTCxJQUFJLEVBQUUsUUFBUTs0QkFDZCxXQUFXLEVBQUUsZ0JBQWdCOzRCQUM3QixRQUFRLEVBQUUsSUFBSTt5QkFDakI7cUJBQ0o7b0JBQ0QsUUFBUSxFQUFFLENBQUMsVUFBVSxDQUFDO2lCQUN6QjtnQkFDRCxRQUFRLEVBQUUsS0FBSyxFQUFFLE1BQVcsRUFBRSxFQUFFO29CQUM1QixJQUFJLENBQUM7d0JBQ0QsTUFBTSxNQUFNLEdBQUcsTUFBTSxLQUFLLENBQ3RCOzRCQUNJLE9BQU8sRUFBRSxNQUFNLENBQUMsUUFBUTs0QkFDeEIsT0FBTyxFQUFFLE1BQU0sQ0FBQyxPQUFPO3lCQUMxQixDQUNKLENBQUE7d0JBQ0QsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLEVBQUUsQ0FBQTtvQkFDL0IsQ0FBQztvQkFBQyxPQUFPLEtBQVUsRUFBRSxDQUFDO3dCQUNsQixNQUFNLENBQUMsS0FBSyxDQUFDLHdCQUF3QixFQUFFLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQzt3QkFDdEQsT0FBTyxJQUFJLENBQUM7b0JBQ2hCLENBQUM7Z0JBQ0wsQ0FBQztnQkFDRCxLQUFLLEVBQUUsSUFBSSxDQUFDLEtBQUs7YUFDcEI7U0FDeUI7UUFDOUI7WUFDSSxJQUFJLEVBQUUsVUFBVTtZQUNoQixRQUFRLEVBQUU7Z0JBQ04sSUFBSSxFQUFFLGVBQWU7Z0JBQ3JCLFdBQVcsRUFBRSwwQ0FBMEM7Z0JBQ3ZELFVBQVUsRUFBRTtvQkFDUixJQUFJLEVBQUUsUUFBUTtvQkFDZCxVQUFVLEVBQUU7d0JBQ1IsT0FBTyxFQUFFOzRCQUNMLElBQUksRUFBRSxRQUFROzRCQUNkLFdBQVcsRUFBRSwwQkFBMEI7eUJBQzFDO3dCQUNELE9BQU8sRUFBRTs0QkFDTCxJQUFJLEVBQUUsT0FBTzs0QkFDYixLQUFLLEVBQUUsRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFOzRCQUN6QixXQUFXLEVBQUUsaUJBQWlCO3lCQUNqQzt3QkFDRCxRQUFRLEVBQUU7NEJBQ04sSUFBSSxFQUFFLFNBQVM7NEJBQ2YsV0FBVyxFQUFFLDJCQUEyQjs0QkFDeEMsUUFBUSxFQUFFLElBQUk7eUJBQ2pCO3FCQUNKO29CQUNELFFBQVEsRUFBRSxDQUFDLFNBQVMsRUFBRSxTQUFTLENBQUM7aUJBQ25DO2dCQUNELFFBQVEsRUFBRSxLQUFLLEVBQUUsTUFBVyxFQUFFLEVBQUU7b0JBQzVCLElBQUksQ0FBQzt3QkFDRCxNQUFNLE1BQU0sR0FBRyxNQUFNLE1BQU0sQ0FDdkI7NEJBQ0ksT0FBTyxFQUFFLE1BQU0sQ0FBQyxPQUFPOzRCQUN2QixPQUFPLEVBQUUsTUFBTSxDQUFDLE9BQU87eUJBQzFCLENBQ0osQ0FBQzt3QkFDRixPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sRUFBRSxDQUFBO29CQUMvQixDQUFDO29CQUFDLE9BQU8sS0FBVSxFQUFFLENBQUM7d0JBQ2xCLE1BQU0sQ0FBQyxLQUFLLENBQUMsNEJBQTRCLEVBQUUsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDO3dCQUMxRCxPQUFPLElBQUksQ0FBQztvQkFDaEIsQ0FBQztnQkFDTCxDQUFDO2dCQUNELEtBQUssRUFBRSxJQUFJLENBQUMsS0FBSzthQUNwQjtTQUN5QjtLQUNqQyxDQUFBO0FBQ0wsQ0FBQyxDQUFBIn0= \ No newline at end of file diff --git a/packages/kbot/dist-in/ai-tools/lib/tools/keyv.d.ts b/packages/kbot/dist-in/ai-tools/lib/tools/keyv.d.ts new file mode 100644 index 00000000..deb738f4 --- /dev/null +++ b/packages/kbot/dist-in/ai-tools/lib/tools/keyv.d.ts @@ -0,0 +1,4 @@ +import Keyv from 'keyv'; +export declare const store: (storePath: string, ns?: string, opts?: any) => Keyv; +export declare const get: (key: string, storePath: string, ns?: string, opts?: any) => Promise; +export declare const set: (key: string, value: any, storePath: string, ns?: string, opts?: any) => Promise; diff --git a/packages/kbot/dist-in/ai-tools/lib/tools/keyv.js b/packages/kbot/dist-in/ai-tools/lib/tools/keyv.js new file mode 100644 index 00000000..af4d4d6f --- /dev/null +++ b/packages/kbot/dist-in/ai-tools/lib/tools/keyv.js @@ -0,0 +1,20 @@ +import * as path from 'path'; +import Keyv from 'keyv'; +import { KeyvFile } from 'keyv-file'; +import { resolve } from '@polymech/commons'; +export const store = (storePath, ns = 'ns-unknown', opts = {}) => { + const keyvFile = new KeyvFile({ + filename: path.resolve(resolve(storePath)), + writeDelay: 100, // ms + }); + return new Keyv({ store: keyvFile, namespace: ns, ...opts }); +}; +export const get = async (key, storePath, ns = 'ns-unknown', opts = {}) => { + const keyv = store(storePath, ns, opts); + return await keyv.get(key); +}; +export const set = async (key, value, storePath, ns = 'ns-unknown', opts = {}) => { + const keyv = store(storePath, ns, opts); + return await keyv.set(key, value); +}; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoia2V5di5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9haS10b29scy9saWIvdG9vbHMva2V5di50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssSUFBSSxNQUFNLE1BQU0sQ0FBQTtBQUM1QixPQUFPLElBQUksTUFBTSxNQUFNLENBQUE7QUFDdkIsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLFdBQVcsQ0FBQTtBQUVwQyxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sbUJBQW1CLENBQUE7QUFFM0MsTUFBTSxDQUFDLE1BQU0sS0FBSyxHQUFHLENBQUMsU0FBaUIsRUFBRSxLQUFhLFlBQVksRUFBRSxPQUFZLEVBQUUsRUFBRSxFQUFFO0lBQ2xGLE1BQU0sUUFBUSxHQUFHLElBQUksUUFBUSxDQUFDO1FBQzFCLFFBQVEsRUFBRSxJQUFJLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUMxQyxVQUFVLEVBQUUsR0FBRyxFQUFFLEtBQUs7S0FDekIsQ0FBQyxDQUFBO0lBQ0YsT0FBTyxJQUFJLElBQUksQ0FBQyxFQUFFLEtBQUssRUFBRSxRQUFRLEVBQUUsU0FBUyxFQUFFLEVBQUUsRUFBRSxHQUFHLElBQUksRUFBRSxDQUFDLENBQUE7QUFDaEUsQ0FBQyxDQUFBO0FBQ0QsTUFBTSxDQUFDLE1BQU0sR0FBRyxHQUFHLEtBQUssRUFBRSxHQUFXLEVBQUUsU0FBaUIsRUFBRSxLQUFhLFlBQVksRUFBRSxPQUFZLEVBQUUsRUFBRSxFQUFFO0lBQ25HLE1BQU0sSUFBSSxHQUFHLEtBQUssQ0FBQyxTQUFTLEVBQUUsRUFBRSxFQUFFLElBQUksQ0FBQyxDQUFBO0lBQ3ZDLE9BQU8sTUFBTSxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFBO0FBQzlCLENBQUMsQ0FBQTtBQUNELE1BQU0sQ0FBQyxNQUFNLEdBQUcsR0FBRyxLQUFLLEVBQUUsR0FBVyxFQUFFLEtBQVUsRUFBRSxTQUFpQixFQUFFLEtBQWEsWUFBWSxFQUFFLE9BQVksRUFBRSxFQUFFLEVBQUU7SUFDL0csTUFBTSxJQUFJLEdBQUcsS0FBSyxDQUFDLFNBQVMsRUFBRSxFQUFFLEVBQUUsSUFBSSxDQUFDLENBQUE7SUFDdkMsT0FBTyxNQUFNLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLEtBQUssQ0FBQyxDQUFBO0FBQ3JDLENBQUMsQ0FBQSJ9 \ No newline at end of file diff --git a/packages/kbot/dist-in/ai-tools/lib/tools/memory.d.ts b/packages/kbot/dist-in/ai-tools/lib/tools/memory.d.ts new file mode 100644 index 00000000..081be802 --- /dev/null +++ b/packages/kbot/dist-in/ai-tools/lib/tools/memory.d.ts @@ -0,0 +1,2 @@ +import { IKBotTask } from '../../types.js'; +export declare const tools: (target: string, options: IKBotTask) => Array; diff --git a/packages/kbot/dist-in/ai-tools/lib/tools/memory.js b/packages/kbot/dist-in/ai-tools/lib/tools/memory.js new file mode 100644 index 00000000..5958c322 --- /dev/null +++ b/packages/kbot/dist-in/ai-tools/lib/tools/memory.js @@ -0,0 +1,354 @@ +import * as path from 'path'; +import { toolLogger } from '../../index.js'; +import { store, get, set } from './keyv.js'; +// Helper function to get storage path +const getStoragePath = (options) => { + // For now, use default path. Later this can be configured via options + return path.join(process.cwd(), 'memory.json'); +}; +// Default collection name when none provided +const DEFAULT_COLLECTION = 'no-collection'; +// Helper function to process value based on format +const processValueForStorage = (value, format) => { + switch (format) { + case 'json': + try { + // Validate JSON by parsing and re-stringifying + JSON.parse(value); + return value; + } + catch (error) { + throw new Error('Invalid JSON format provided'); + } + case 'binary': + // For binary, we expect base64 encoded data + try { + // Validate base64 + Buffer.from(value, 'base64'); + return value; + } + catch (error) { + throw new Error('Invalid base64 format for binary data'); + } + case 'text': + default: + return value; + } +}; +// Helper function to create memory entry +const createMemoryEntry = (value, format) => { + const now = new Date().toISOString(); + return { + value: processValueForStorage(value, format), + meta: { + type: format, + created: now, + updated: now + } + }; +}; +export const tools = (target, options) => { + const logger = toolLogger('memory', options); + const storagePath = getStoragePath(options); + return [ + { + type: 'function', + function: { + name: 'memorize', + description: `Store information in memory as a key-value collection with format support. Supports text, JSON, and binary (base64) formats. + +Returns: { + success: boolean, + message: string, + meta: { + type: "text" | "json" | "binary", + created: string (ISO timestamp), + updated: string (ISO timestamp) + } +}`, + parameters: { + type: 'object', + properties: { + collection: { + type: 'string', + description: 'Collection name to organize related data (defaults to "no-collection" if not provided). Acts like a namespace.', + optional: true + }, + key: { + type: 'string', + description: 'Unique identifier for the data within the collection. Must be a string.' + }, + value: { + type: 'string', + description: 'The data to store. For format="text": any string. For format="json": valid JSON string. For format="binary": base64 encoded data.' + }, + format: { + type: 'string', + description: 'Data format type. "text" for plain text (default), "json" for JSON data (validates structure), "binary" for base64 encoded binary data.', + enum: ['text', 'json', 'binary'], + optional: true + } + }, + required: ['key', 'value'] + }, + function: async (params) => { + try { + const { collection = DEFAULT_COLLECTION, key, value, format = 'text' } = params; + logger.debug(`Tool::Memorize Storing ${key} in collection ${collection} as ${format}`); + const memoryEntry = createMemoryEntry(value, format); + await set(`${collection}:${key}`, memoryEntry, storagePath, collection); + return { + success: true, + message: `Stored ${key} in collection ${collection} as ${format}`, + meta: memoryEntry.meta + }; + } + catch (error) { + logger.error('Error storing memory', error); + return { + success: false, + message: error instanceof Error ? error.message : 'Unknown error occurred' + }; + } + }, + parse: JSON.parse + } + }, + { + type: 'function', + function: { + name: 'recall', + description: `Retrieve stored information from memory by collection and key, including format metadata. + +Returns: { + success: boolean, + value?: string (the stored data), + meta?: { + type: "text" | "json" | "binary", + created: string (ISO timestamp), + updated: string (ISO timestamp) + }, + key: string, + collection: string, + message?: string (error message if success=false) +}`, + parameters: { + type: 'object', + properties: { + collection: { + type: 'string', + description: 'Collection name to retrieve from (defaults to "no-collection" if not provided). Must match the collection used when storing.', + optional: true + }, + key: { + type: 'string', + description: 'The unique identifier of the data to retrieve. Must match the key used when storing.' + } + }, + required: ['key'] + }, + function: async (params) => { + try { + const { collection = DEFAULT_COLLECTION, key } = params; + logger.debug(`Tool::Recall Retrieving ${key} from collection ${collection}`); + const storedData = await get(`${collection}:${key}`, storagePath, collection); + if (storedData === undefined) { + return { success: false, message: `Key ${key} not found in collection ${collection}` }; + } + // Handle both old format (plain string) and new format (MemoryEntry) + let memoryEntry; + if (typeof storedData === 'string') { + // Legacy format - convert to new format + memoryEntry = { + value: storedData, + meta: { + type: 'text', + created: new Date().toISOString(), + updated: new Date().toISOString() + } + }; + } + else { + memoryEntry = storedData; + } + return { + success: true, + value: memoryEntry.value, + meta: memoryEntry.meta, + key, + collection + }; + } + catch (error) { + logger.error('Error retrieving memory', error); + return { + success: false, + message: error instanceof Error ? error.message : 'Unknown error occurred' + }; + } + }, + parse: JSON.parse + } + }, + { + type: 'function', + function: { + name: 'forget', + description: `Remove a specific key from memory collection. + +Returns: { + success: boolean, + message: string (confirmation or error message) +}`, + parameters: { + type: 'object', + properties: { + collection: { + type: 'string', + description: 'Collection name to remove from (defaults to "no-collection" if not provided). Must match the collection where the key was stored.', + optional: true + }, + key: { + type: 'string', + description: 'The unique identifier of the data to remove. Must match exactly the key used when storing.' + } + }, + required: ['key'] + }, + function: async (params) => { + try { + const { collection = DEFAULT_COLLECTION, key } = params; + logger.debug(`Tool::Forget Removing ${key} from collection ${collection}`); + const keyv = store(storagePath, collection); + const deleted = await keyv.delete(`${collection}:${key}`); + return { success: deleted, message: deleted ? `Removed ${key} from ${collection}` : `Key ${key} not found in ${collection}` }; + } + catch (error) { + logger.error('Error removing from memory', error); + return { + success: false, + message: error instanceof Error ? error.message : 'Unknown error occurred' + }; + } + }, + parse: JSON.parse + } + }, + { + type: 'function', + function: { + name: 'list_memories', + description: `List all keys in a specific collection using Keyv's iterator method. + +Returns: { + success: boolean, + collection: string (the collection name), + keys: string[] (array of key names in the collection), + entries: Array<{ + key: string, + meta?: { + type: "text" | "json" | "binary", + created: string (ISO timestamp), + updated: string (ISO timestamp) + } + }>, + count: number (total number of keys), + message?: string (info or error message) +}`, + parameters: { + type: 'object', + properties: { + collection: { + type: 'string', + description: 'Collection name to list keys from (defaults to "no-collection" if not provided). Will return all keys stored in this collection namespace.', + optional: true + } + }, + required: [] + }, + function: async (params) => { + try { + const { collection = DEFAULT_COLLECTION } = params; + logger.debug(`Tool::ListMemories Listing keys in collection ${collection}`); + // Create a Keyv instance for the specific collection to use iterator + const keyv = store(storagePath, collection); + const keys = []; + const entries = []; + try { + // Check if iterator method exists and use it + if (typeof keyv.iterator === 'function') { + try { + // Try calling iterator without arguments first + const iterator = keyv.iterator(); + for await (const [key, value] of iterator) { + // Remove the collection prefix from the key to get the clean key name + const cleanKey = key.replace(`${collection}:`, ''); + keys.push(cleanKey); + // Try to extract metadata if it's a MemoryEntry + let meta = undefined; + if (value && typeof value === 'object' && value.meta) { + meta = value.meta; + } + entries.push({ key: cleanKey, meta }); + } + } + catch (iteratorCallError) { + logger.warn(`Tool::ListMemories Iterator call failed:`, iteratorCallError); + // Fall through to the not available case + return { + success: true, + collection, + keys: [], + entries: [], + count: 0, + message: 'Iterator call failed. Unable to list keys.' + }; + } + } + else { + // Iterator not available, provide helpful message + logger.warn(`Tool::ListMemories Iterator method not available for Keyv instance`); + return { + success: true, + collection, + keys: [], + entries: [], + count: 0, + message: 'Iterator method not available in this Keyv version. Use individual key operations instead.' + }; + } + return { + success: true, + collection, + keys, + entries, + count: keys.length + }; + } + catch (iteratorError) { + // If iterator fails, fall back to returning basic info + logger.warn(`Tool::ListMemories Iterator failed for collection ${collection}:`, iteratorError); + return { + success: true, + collection, + keys: [], + entries: [], + count: 0, + message: 'Iterator failed or collection is empty' + }; + } + } + catch (error) { + logger.error('Error listing memories', error); + return { + success: false, + message: error instanceof Error ? error.message : 'Unknown error occurred' + }; + } + }, + parse: JSON.parse + } + } + ]; +}; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWVtb3J5LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2FpLXRvb2xzL2xpYi90b29scy9tZW1vcnkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLElBQUksTUFBTSxNQUFNLENBQUE7QUFJNUIsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGdCQUFnQixDQUFBO0FBRzNDLE9BQU8sRUFBRSxLQUFLLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxNQUFNLFdBQVcsQ0FBQTtBQUUzQyxzQ0FBc0M7QUFDdEMsTUFBTSxjQUFjLEdBQUcsQ0FBQyxPQUFrQixFQUFVLEVBQUU7SUFDbEQsc0VBQXNFO0lBQ3RFLE9BQU8sSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxFQUFFLEVBQUUsYUFBYSxDQUFDLENBQUM7QUFDbkQsQ0FBQyxDQUFDO0FBRUYsNkNBQTZDO0FBQzdDLE1BQU0sa0JBQWtCLEdBQUcsZUFBZSxDQUFDO0FBZTNDLG1EQUFtRDtBQUNuRCxNQUFNLHNCQUFzQixHQUFHLENBQUMsS0FBYSxFQUFFLE1BQWtCLEVBQVUsRUFBRTtJQUN6RSxRQUFRLE1BQU0sRUFBRSxDQUFDO1FBQ2IsS0FBSyxNQUFNO1lBQ1AsSUFBSSxDQUFDO2dCQUNELCtDQUErQztnQkFDL0MsSUFBSSxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQztnQkFDbEIsT0FBTyxLQUFLLENBQUM7WUFDakIsQ0FBQztZQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7Z0JBQ2IsTUFBTSxJQUFJLEtBQUssQ0FBQyw4QkFBOEIsQ0FBQyxDQUFDO1lBQ3BELENBQUM7UUFDTCxLQUFLLFFBQVE7WUFDVCw0Q0FBNEM7WUFDNUMsSUFBSSxDQUFDO2dCQUNELGtCQUFrQjtnQkFDbEIsTUFBTSxDQUFDLElBQUksQ0FBQyxLQUFLLEVBQUUsUUFBUSxDQUFDLENBQUM7Z0JBQzdCLE9BQU8sS0FBSyxDQUFDO1lBQ2pCLENBQUM7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 \ No newline at end of file diff --git a/packages/kbot/dist-in/ai-tools/lib/tools/npm.d.ts b/packages/kbot/dist-in/ai-tools/lib/tools/npm.d.ts new file mode 100644 index 00000000..081be802 --- /dev/null +++ b/packages/kbot/dist-in/ai-tools/lib/tools/npm.d.ts @@ -0,0 +1,2 @@ +import { IKBotTask } from '../../types.js'; +export declare const tools: (target: string, options: IKBotTask) => Array; diff --git a/packages/kbot/dist-in/ai-tools/lib/tools/npm.js b/packages/kbot/dist-in/ai-tools/lib/tools/npm.js new file mode 100644 index 00000000..abd3ee88 --- /dev/null +++ b/packages/kbot/dist-in/ai-tools/lib/tools/npm.js @@ -0,0 +1,150 @@ +import { exec } from 'child_process'; +import { promisify } from 'util'; +import { logger } from '../../index.js'; +import pMap from "p-map"; +import { sync as exists } from '@polymech/fs/exists'; +import { toolLogger } from '../../index.js'; +const execAsync = promisify(exec); +const install = async (dependency, directory) => { + return new Promise((resolve, reject) => { + const command = `pnpm add ${dependency} --dir ${directory}`; + exec(command, (error, stdout, stderr) => { + if (error) { + logger.error(`Error installing ${dependency}:`, error.message); + return resolve(false); + } + logger.info(`Successfully installed "${dependency}" in "${directory}".`); + }); + }); +}; +export const tools = (target, options) => { + const logger = toolLogger('npm', options); + return [ + { + type: 'function', + function: { + name: 'build_project', + description: 'Build project using pnpm build command', + parameters: { + type: 'object', + properties: {}, + required: [] + }, + function: async () => { + try { + logger.debug(`Tool::BuildProject Building project at ${target}`); + const { stdout, stderr } = await execAsync('pnpm build', { + cwd: target + }); + return { + success: !stderr, + output: stdout, + error: stderr || null + }; + } + catch (error) { + logger.error('Error building project', error); + return { + success: false, + output: null, + error: error.message + }; + } + }, + parse: JSON.parse + } + }, + { + type: 'function', + function: { + name: 'run_npm', + description: 'Run an npm/pnpm command', + parameters: { + type: 'object', + properties: { + command: { type: 'string', description: 'Command to run (e.g. install, test, etc)' }, + args: { + type: 'array', + items: { type: 'string' }, + description: 'Additional arguments for the command', + optional: true + } + }, + required: ['command'] + }, + function: async (params) => { + try { + const args = params.args ? params.args.join(' ') : ''; + const fullCommand = `pnpm ${params.command} ${args}`.trim(); + logger.debug(`Tool::RunNpm Running command: ${fullCommand}`); + const { stdout, stderr } = await execAsync(fullCommand, { + cwd: target + }); + return { + success: !stderr, + output: stdout, + error: stderr || null + }; + } + catch (error) { + logger.error('Error running npm command', error); + return { + success: false, + output: null, + error: error.message + }; + } + }, + parse: JSON.parse + } + }, + { + type: 'function', + function: { + name: "install_dependency", + description: "Install a dependency using npm", + parameters: { + type: "object", + properties: { + dependencies: { + type: "array", + items: { + type: "string" + } + } + }, + required: ["dependencies"], + }, + function: async (ret) => { + try { + const { dependencies } = ret; + if (!target) { + logger.error(`Tool::NPM Target is required to install dependencies`); + return; + } + if (!exists(target)) { + logger.error(`Project doesnt path exists ${target}`); + return; + } + await pMap(dependencies, (async (dependency) => { + logger.info(`Installing dependency`, dependency); + try { + return install(dependency, target); + } + catch (error) { + logger.error(`Error installing dependency ${dependency} `, error); + } + }), { + concurrency: 1 + }); + } + catch (error) { + logger.error(`Error installing dependencies`, error); + } + }, + parse: JSON.parse, + } + } + ]; +}; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibnBtLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2FpLXRvb2xzL2xpYi90b29scy9ucG0udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBRUEsT0FBTyxFQUFFLElBQUksRUFBRSxNQUFNLGVBQWUsQ0FBQTtBQUNwQyxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sTUFBTSxDQUFBO0FBQ2hDLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQTtBQUN2QyxPQUFPLElBQUksTUFBTSxPQUFPLENBQUE7QUFDeEIsT0FBTyxFQUFFLElBQUksSUFBSSxNQUFNLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQTtBQUVwRCxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sZ0JBQWdCLENBQUE7QUFFM0MsTUFBTSxTQUFTLEdBQUcsU0FBUyxDQUFDLElBQUksQ0FBQyxDQUFBO0FBQ2pDLE1BQU0sT0FBTyxHQUFHLEtBQUssRUFBRSxVQUFrQixFQUFFLFNBQWlCLEVBQWdCLEVBQUU7SUFDMUUsT0FBTyxJQUFJLE9BQU8sQ0FBQyxDQUFDLE9BQU8sRUFBRSxNQUFNLEVBQUUsRUFBRTtRQUNuQyxNQUFNLE9BQU8sR0FBRyxZQUFZLFVBQVUsVUFBVSxTQUFTLEVBQUUsQ0FBQTtRQUMzRCxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUMsS0FBSyxFQUFFLE1BQU0sRUFBRSxNQUFNLEVBQUUsRUFBRTtZQUNwQyxJQUFJLEtBQUssRUFBRSxDQUFDO2dCQUNSLE1BQU0sQ0FBQyxLQUFLLENBQUMsb0JBQW9CLFVBQVUsR0FBRyxFQUFFLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQTtnQkFDOUQsT0FBTyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUE7WUFDekIsQ0FBQztZQUNELE1BQU0sQ0FBQyxJQUFJLENBQUMsMkJBQTJCLFVBQVUsU0FBUyxTQUFTLElBQUksQ0FBQyxDQUFBO1FBQzVFLENBQUMsQ0FBQyxDQUFBO0lBQ04sQ0FBQyxDQUFDLENB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 \ No newline at end of file diff --git a/packages/kbot/dist-in/ai-tools/lib/tools/process.d.ts b/packages/kbot/dist-in/ai-tools/lib/tools/process.d.ts new file mode 100644 index 00000000..1ec9aaa8 --- /dev/null +++ b/packages/kbot/dist-in/ai-tools/lib/tools/process.d.ts @@ -0,0 +1,16 @@ +export declare enum STATUS { + OK = 0, + ERROR = 1, + PENDING = 2 +} +export declare class Process { + binary: string; + cwd: string; + args: string; + buffer: string[]; + constructor(options?: any); + exec(command: string, args?: string[]): Promise; +} +export declare class Helper { + static run(cwd: any, cmd: string, args: string[], buffer?: string[], debug_stream?: boolean): Promise; +} diff --git a/packages/kbot/dist-in/ai-tools/lib/tools/process.js b/packages/kbot/dist-in/ai-tools/lib/tools/process.js new file mode 100644 index 00000000..10deea0e --- /dev/null +++ b/packages/kbot/dist-in/ai-tools/lib/tools/process.js @@ -0,0 +1,126 @@ +import { logger } from '../../index.js'; +import { spawn } from 'child_process'; +export var STATUS; +(function (STATUS) { + STATUS[STATUS["OK"] = 0] = "OK"; + STATUS[STATUS["ERROR"] = 1] = "ERROR"; + STATUS[STATUS["PENDING"] = 2] = "PENDING"; +})(STATUS || (STATUS = {})); +const fatalHandler = (message, fn) => { + if (message.startsWith('fatal:')) { + fn('\t\ ' + message); + return true; + } + return false; +}; +const defaultFilter = (message) => { + return message.length > 0 && + message !== '\n' && + message !== '\r' && + message !== '\r\n' && + !message.startsWith('Debugger attached') && + !message.includes('NODE_TLS_REJECT_UNAUTHORIZED') && + !message.includes('Waiting for the debugger to disconnect'); +}; +const subscribe = (signal, collector = () => { }) => { + if (!signal || !signal.on) { + return; + } + signal.on('message', (message) => logger.debug('message', message)); + signal.on('error', (error) => logger.error('std-error', error)); + signal.on('data', (data) => { + /* + const msg = data.toString().replace(ansiRegex(), "") + if (!defaultFilter(msg)) { + return + } + collector(msg)*/ + process.stdout.write(data); + }); +}; +const merge = (buffer, data) => buffer.concat(data); +const hook = (child, resolve, reject, cmd, buffer = []) => { + const collector = (data) => { buffer.push(data); }; + //subscribe(child.stderr, collector) + //process.stdin.pipe(child.stdin) + debugger; + child.on('exit', (code, signal) => { + debugger; + if (code) { + resolve({ + code: STATUS.ERROR, + command: cmd, + error: code, + messages: buffer + }); + } + else { + resolve({ + code: STATUS.OK, + command: cmd, + messages: buffer + }); + } + }); + return child; +}; +export class Process { + binary = ''; + cwd = ''; + args = ''; + buffer = []; + constructor(options = {}) { + this.binary = options.binary || this.binary; + this.cwd = options.cwd || process.cwd(); + this.buffer = options.buffer || []; + } + async exec(command, args = []) { + args = [command].concat(args); + try { + let cmd = `${this.binary} ${args.join(' ')}`; + /* + const p = new Promise((resolve, reject) => { + const p = exec(cmd, { + cwd: this.cwd + }) + return hook(p, resolve, reject, this.binary + ' ' + args.join(' '), this.buffer) + }) + return p + */ + try { + //stdio: ['pipe', 'pipe', 'pipe'], + debugger; + const p = new Promise((resolve, reject) => { + const cp = spawn(cmd, args, { + cwd: this.cwd, + shell: true, + stdio: 'inherit', + env: { + ...process.env + }, + }); + return hook(cp, resolve, reject, cmd, this.buffer); + }); + return p; + } + catch (e) { + logger.error('Error executing command', e); + } + } + catch (e) { + logger.error('Error executing command', e); + } + } +} +export class Helper { + static async run(cwd, cmd, args, buffer = [], debug_stream = false) { + debug_stream && logger.info(`Run ${cmd} in ${cwd}`, args); + const gitProcess = new Process({ + cwd, + binary: cmd, + buffer + }); + return gitProcess.exec('', args); + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJvY2Vzcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9haS10b29scy9saWIvdG9vbHMvcHJvY2Vzcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sZ0JBQWdCLENBQUE7QUFFdkMsT0FBTyxFQUFnQixLQUFLLEVBQUUsTUFBTSxlQUFlLENBQUE7QUFFbkQsTUFBTSxDQUFOLElBQVksTUFJWDtBQUpELFdBQVksTUFBTTtJQUNkLCtCQUFFLENBQUE7SUFDRixxQ0FBSyxDQUFBO0lBQ0wseUNBQU8sQ0FBQTtBQUNYLENBQUMsRUFKVyxNQUFNLEtBQU4sTUFBTSxRQUlqQjtBQUVELE1BQU0sWUFBWSxHQUFHLENBQUMsT0FBZSxFQUFFLEVBQXlCLEVBQVcsRUFBRTtJQUN6RSxJQUFJLE9BQU8sQ0FBQyxVQUFVLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQztRQUMvQixFQUFFLENBQUMsTUFBTSxHQUFHLE9BQU8sQ0FBQyxDQUFBO1FBQ3BCLE9BQU8sSUFBSSxDQUFDO0lBQ2hCLENBQUM7SUFDRCxPQUFPLEtBQUssQ0FBQTtBQUNoQixDQUFDLENBQUE7QUFFRCxNQUFNLGFBQWEsR0FBRyxDQUFDLE9BQWUsRUFBVyxFQUFFO0lBQy9DLE9BQU8sT0FBTyxDQUFDLE1BQU0sR0FBRyxDQUFDO1FBQ3JCLE9BQU8sS0FBSyxJQUFJO1FBQ2hCLE9BQU8sS0FBSyxJQUFJO1FBQ2hCLE9BQU8sS0FBSyxNQUFNO1FBQ2xCLENBQUMsT0FBTyxDQUFDLFVBQVUsQ0FBQyxtQkFBbUIsQ0FBQztRQUN4QyxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsOEJBQThCLENBQUM7UUFDakQsQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLHdDQUF3QyxDQUFDLENBQUE7QUFDbkUsQ0FBQyxDQUFBO0FBRUQsTUFBTSxTQUFTLEdBQUcsQ0FBQyxNQUF1QixFQUFFLFlBQWlDLEdBQUcsRUFBRSxHQUFHLENB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 \ No newline at end of file diff --git a/packages/kbot/dist-in/ai-tools/lib/tools/search.d.ts b/packages/kbot/dist-in/ai-tools/lib/tools/search.d.ts new file mode 100644 index 00000000..081be802 --- /dev/null +++ b/packages/kbot/dist-in/ai-tools/lib/tools/search.d.ts @@ -0,0 +1,2 @@ +import { IKBotTask } from '../../types.js'; +export declare const tools: (target: string, options: IKBotTask) => Array; diff --git a/packages/kbot/dist-in/ai-tools/lib/tools/search.js b/packages/kbot/dist-in/ai-tools/lib/tools/search.js new file mode 100644 index 00000000..a3c110f6 --- /dev/null +++ b/packages/kbot/dist-in/ai-tools/lib/tools/search.js @@ -0,0 +1,90 @@ +import { isArray } from '@polymech/core/primitives'; +import { CONFIG_DEFAULT } from '@polymech/commons'; +import { toolLogger } from '../../index.js'; +export const tools = (target, options) => { + const logger = toolLogger('search', options); + return [ + { + type: 'function', + function: { + name: 'google', + description: 'Searches Google for the given query', + parameters: { + type: 'object', + properties: { + query: { type: 'string' } + }, + required: ['query'] + }, + function: async (params) => { + const { query } = params; + const config = CONFIG_DEFAULT(); + let apiKey = config?.google?.api_key; + let cse = config?.google?.cse; + if (!config || !apiKey || !cse) { + logger.debug("Config not found in $HOME/.osr/config.json. " + + "Optionally, export OSR_CONFIG with the path to the configuration file " + + ""); + return undefined; + } + const res = await fetch(`https://www.googleapis.com/customsearch/v1?key=${apiKey}&cx=${cse}&q=${encodeURIComponent(query)}`); + const data = await res.json(); + let results = data.items?.map((item) => ({ + title: item.title, + link: item.link, + snippet: item.snippet, + ...item + })) ?? []; + return JSON.stringify(results); + }, + parse: JSON.parse + } + }, + { + type: 'function', + function: { + name: 'serpapi', + description: 'Searches Serpapi (finds locations (engine:google_local), places on the map (engine:google_maps) ) for the given query', + parameters: { + type: 'object', + properties: { + query: { type: 'string' }, + engine: { type: 'string', default: 'google' }, + }, + required: ['query'] + }, + function: async (params) => { + const { query, engine } = params; + const config = CONFIG_DEFAULT(); + let apiKey = config?.serpapi?.key || config?.serpapi?.api_key; + if (!config || !apiKey) { + logger.debug("Config not found in $HOME/.osr/config.json. " + + "Optionally, export OSR_CONFIG with the path to the configuration file " + + ""); + return undefined; + } + const url = `https://serpapi.com/search?api_key=${apiKey}&engine=${engine || 'google'}&q=${encodeURIComponent(query)}&google_domain=google.com`; + const res = await fetch(url); + logger.debug(`Searching ${url}`); + if (!res.ok) { + throw new Error(`HTTP error! status: ${res.status}`); + } + const data = await res.json(); + let items = data.organic_results || data.local_results || data.place_results || data.places || data.maps_results || []; + if (items && !isArray(items)) { + items = [items]; + } + let results = items.map((item) => ({ + title: item.title, + link: item.link, + snippet: item.snippet, + ...item + })) ?? []; + return JSON.stringify(results); + }, + parse: JSON.parse + } + } + ]; +}; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VhcmNoLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2FpLXRvb2xzL2xpYi90b29scy9zZWFyY2gudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBRUEsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLDJCQUEyQixDQUFBO0FBQ25ELE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQTtBQUNsRCxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sZ0JBQWdCLENBQUE7QUFHM0MsTUFBTSxDQUFDLE1BQU0sS0FBSyxHQUFHLENBQUMsTUFBYyxFQUFFLE9BQWtCLEVBQWMsRUFBRTtJQUNwRSxNQUFNLE1BQU0sR0FBRyxVQUFVLENBQUMsUUFBUSxFQUFFLE9BQU8sQ0FBQyxDQUFBO0lBQzVDLE9BQU87UUFDSDtZQUNJLElBQUksRUFBRSxVQUFVO1lBQ2hCLFFBQVEsRUFBRTtnQkFDTixJQUFJLEVBQUUsUUFBUTtnQkFDZCxXQUFXLEVBQUUscUNBQXFDO2dCQUNsRCxVQUFVLEVBQUU7b0JBQ1IsSUFBSSxFQUFFLFFBQVE7b0JBQ2QsVUFBVSxFQUFFO3dCQUNSLEtBQUssRUFBRSxFQUFFLElBQUksRUFBRSxRQUFRLEVBQUU7cUJBQzVCO29CQUNELFFBQVEsRUFBRSxDQUFDLE9BQU8sQ0FBQztpQkFDdEI7Z0JBQ0QsUUFBUSxFQUFFLEtBQUssRUFBRSxNQUFXLEVBQUUsRUFBRTtvQkFDNUIsTUFBTSxFQUFFLEtBQUssRUFBRSxHQUFHLE1BQU0sQ0FBQTtvQkFDeEIsTUFBTSxNQUFNLEdBQUcsY0FBYyxFQUFTLENBQUE7b0JBQ3RDLElBQUksTUFBTSxHQUFHLE1BQU0sRUFBRSxNQUFNLEVBQUUsT0FBTyxDQUFBO29CQUNwQyxJQUFJLEdBQUcsR0FBRyxNQUFNLEVBQUUsTUFBTSxFQUFFLEdBQUcsQ0FBQTtvQkFDN0IsSUFBSSxDQUFDLE1BQU0sSUFBSSxDQUFDLE1BQU0sSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDO3dC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 \ No newline at end of file diff --git a/packages/kbot/dist-in/ai-tools/lib/tools/terminal.d.ts b/packages/kbot/dist-in/ai-tools/lib/tools/terminal.d.ts new file mode 100644 index 00000000..081be802 --- /dev/null +++ b/packages/kbot/dist-in/ai-tools/lib/tools/terminal.d.ts @@ -0,0 +1,2 @@ +import { IKBotTask } from '../../types.js'; +export declare const tools: (target: string, options: IKBotTask) => Array; diff --git a/packages/kbot/dist-in/ai-tools/lib/tools/terminal.js b/packages/kbot/dist-in/ai-tools/lib/tools/terminal.js new file mode 100644 index 00000000..e14d462c --- /dev/null +++ b/packages/kbot/dist-in/ai-tools/lib/tools/terminal.js @@ -0,0 +1,116 @@ +import * as path from 'path'; +import { spawn } from 'child_process'; +import { toolLogger } from '../../index.js'; +import { Helper } from './process.js'; +export const tools = (target, options) => { + const logger = toolLogger('terminal', options); + return [ + { + type: 'function', + function: { + name: 'execute_command', + description: 'Execute a terminal command and capture output', + parameters: { + type: 'object', + properties: { + command: { + type: 'string', + description: 'Command to execute' + }, + args: { + type: 'array', + items: { type: 'string' }, + description: 'Command arguments', + optional: true + }, + cwd: { + type: 'string', + description: 'Working directory for command execution', + optional: true + }, + background: { + type: 'boolean', + description: 'Run command in background (non-blocking)', + optional: true, + default: false + }, + window: { + type: 'boolean', + description: 'Open command in new terminal window', + optional: true, + default: false + }, + detached: { + type: 'boolean', + description: 'Run process detached from parent', + optional: true, + default: false + } + }, + required: ['command'] + }, + function: async (params) => { + try { + debugger; + const cwd = params.cwd ? path.join(target, params.cwd) : target; + const args = params.args || []; + logger.debug(`Tool::Terminal : ExecuteCommand Running '${params.command}' in ${cwd}`, params); + if (params.detached) { + const isWindows = process.platform === 'win32'; + if (isWindows) { + spawn('cmd', ['/c', 'start', 'cmd', '/k', params.command, ...args], { + cwd: cwd, + detached: true, + stdio: 'ignore' + }); + } + else { + // For macOS/Linux + spawn('x-terminal-emulator', ['-e', `${params.command} ${args.join(' ')}`], { + cwd: cwd, + detached: true, + stdio: 'ignore' + }); + } + return { + success: true, + output: 'Command launched in new window', + error: null + }; + } + if (params.background || params.detached) { + const child = spawn(params.command, args, { + cwd: cwd, + detached: params.detached === true, + stdio: 'ignore' + }); + if (params.detached) { + child.unref(); + } + return { + success: true, + output: `Process started with PID: ${child.pid}`, + error: null + }; + } + const cmd = `${params.command} ${args.join(' ')}`.trim(); + logger.debug(`Tool::ExecuteCommand Running '${cmd}' in ${cwd}`); + const collector = []; + const ret = await Helper.run(cwd, cmd, [], collector, true); + return ret; + } + catch (error) { + logger.error('Error executing command', error); + return { + success: false, + output: null, + error: error.message + }; + } + }, + parse: JSON.parse + } + } + ]; +}; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGVybWluYWwuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvYWktdG9vbHMvbGliL3Rvb2xzL3Rlcm1pbmFsLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxJQUFJLE1BQU0sTUFBTSxDQUFBO0FBRTVCLE9BQU8sRUFBRSxLQUFLLEVBQUUsTUFBTSxlQUFlLENBQUE7QUFDckMsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGdCQUFnQixDQUFBO0FBRTNDLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxjQUFjLENBQUE7QUFFckMsTUFBTSxDQUFDLE1BQU0sS0FBSyxHQUFHLENBQUMsTUFBYyxFQUFFLE9BQWtCLEVBQWMsRUFBRTtJQUNwRSxNQUFNLE1BQU0sR0FBRyxVQUFVLENBQUMsVUFBVSxFQUFFLE9BQU8sQ0FBQyxDQUFBO0lBQzlDLE9BQU87UUFDSDtZQUNJLElBQUksRUFBRSxVQUFVO1lBQ2hCLFFBQVEsRUFBRTtnQkFDTixJQUFJLEVBQUUsaUJBQWlCO2dCQUN2QixXQUFXLEVBQUUsK0NBQStDO2dCQUM1RCxVQUFVLEVBQUU7b0JBQ1IsSUFBSSxFQUFFLFFBQVE7b0JBQ2QsVUFBVSxFQUFFO3dCQUNSLE9BQU8sRUFBRTs0QkFDTCxJQUFJLEVBQUUsUUFBUTs0QkFDZCxXQUFXLEVBQUUsb0JBQW9CO3lCQUNwQzt3QkFDRCxJQUFJLEVBQUU7NEJBQ0YsSUFBSSxFQUFFLE9BQU87NEJBQ2IsS0FBSyxFQUFFLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRTs0QkFDekIsV0FBVyxFQUFFLG1CQUFtQjs0QkFDaEMsUUFBUSxFQUFFLElBQUk7eUJBQ2pCO3dCQUNELEdBQUcsRUFBRTs0QkFDRCxJQUFJLEVBQUUsUUFBUTs0QkFDZCxXQUFXLEVBQUUseUNBQXlDOzRCQUN0RCxRQUFRLEVBQUUsSUFBSTt5QkFDakI7d0JBQ0QsVUFBVSxFQUFFOzRCQUNSLElBQUksRUFBRSxTQUFTOzRCQUNmLFdBQVcs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 \ No newline at end of file diff --git a/packages/kbot/dist-in/ai-tools/lib/tools/tools.d.ts b/packages/kbot/dist-in/ai-tools/lib/tools/tools.d.ts new file mode 100644 index 00000000..edd1da0d --- /dev/null +++ b/packages/kbot/dist-in/ai-tools/lib/tools/tools.d.ts @@ -0,0 +1,10 @@ +export declare const tools: { + fs: (target: string, options: import("../../types.js").IKBotTask) => Array; + npm: (target: string, options: import("../../types.js").IKBotTask) => Array; + git: (target: string, options: import("../../types.js").IKBotTask) => Array; + terminal: (target: string, options: import("../../types.js").IKBotTask) => Array; + interact: (target: string, options: import("../../types.js").IKBotTask) => Array; + user: (target: string, options: import("../../types.js").IKBotTask) => Array; + search: (target: string, options: import("../../types.js").IKBotTask) => Array; + memory: (target: string, options: import("../../types.js").IKBotTask) => Array; +}; diff --git a/packages/kbot/dist-in/ai-tools/lib/tools/tools.js b/packages/kbot/dist-in/ai-tools/lib/tools/tools.js new file mode 100644 index 00000000..7aa1f01a --- /dev/null +++ b/packages/kbot/dist-in/ai-tools/lib/tools/tools.js @@ -0,0 +1,23 @@ +import { tools as fsTools } from './fs.js'; +import { tools as npmTools } from './npm.js'; +import { tools as gitTools } from './git.js'; +import { tools as terminalTools } from './terminal.js'; +import { tools as interactTools } from './interact.js'; +import { tools as userTools } from './user.js'; +import { tools as search } from './search.js'; +//import { tools as webTools } from './web.js' +import { tools as memoryTools } from './memory.js'; +// import { tools as emailTools } from './email' +export const tools = { + fs: fsTools, + npm: npmTools, + git: gitTools, + terminal: terminalTools, + interact: interactTools, + user: userTools, + search: search, + // web: webTools, + memory: memoryTools + // email: emailTools +}; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidG9vbHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvYWktdG9vbHMvbGliL3Rvb2xzL3Rvb2xzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxLQUFLLElBQUksT0FBTyxFQUFFLE1BQU0sU0FBUyxDQUFBO0FBQzFDLE9BQU8sRUFBRSxLQUFLLElBQUksUUFBUSxFQUFFLE1BQU0sVUFBVSxDQUFBO0FBQzVDLE9BQU8sRUFBRSxLQUFLLElBQUksUUFBUSxFQUFFLE1BQU0sVUFBVSxDQUFBO0FBQzVDLE9BQU8sRUFBRSxLQUFLLElBQUksYUFBYSxFQUFFLE1BQU0sZUFBZSxDQUFBO0FBQ3RELE9BQU8sRUFBRSxLQUFLLElBQUksYUFBYSxFQUFFLE1BQU0sZUFBZSxDQUFBO0FBQ3RELE9BQU8sRUFBRSxLQUFLLElBQUksU0FBUyxFQUFFLE1BQU0sV0FBVyxDQUFBO0FBQzlDLE9BQU8sRUFBRSxLQUFLLElBQUksTUFBTSxFQUFFLE1BQU0sYUFBYSxDQUFBO0FBQzdDLDhDQUE4QztBQUM5QyxPQUFPLEVBQUUsS0FBSyxJQUFJLFdBQVcsRUFBRSxNQUFNLGFBQWEsQ0FBQTtBQUNsRCxnREFBZ0Q7QUFFaEQsTUFBTSxDQUFDLE1BQU0sS0FBSyxHQUFHO0lBQ2pCLEVBQUUsRUFBRSxPQUFPO0lBQ1gsR0FBRyxFQUFFLFFBQVE7SUFDYixHQUFHLEVBQUUsUUFBUTtJQUNiLFFBQVEsRUFBRSxhQUFhO0lBQ3ZCLFFBQVEsRUFBRSxhQUFhO0lBQ3ZCLElBQUksRUFBRSxTQUFTO0lBQ2YsTUFBTSxFQUFFLE1BQU07SUFDZCxpQkFBaUI7SUFDakIsTUFBTSxFQUFFLFdBQVc7SUFDbkIsb0JBQW9CO0NBQ3ZCLENBQUEifQ== \ No newline at end of file diff --git a/packages/kbot/dist-in/ai-tools/lib/tools/user.d.ts b/packages/kbot/dist-in/ai-tools/lib/tools/user.d.ts new file mode 100644 index 00000000..e750843f --- /dev/null +++ b/packages/kbot/dist-in/ai-tools/lib/tools/user.d.ts @@ -0,0 +1,4 @@ +import { IKBotTask } from '../../types.js'; +export declare const mime: (file?: string) => any; +export declare const fileToBase64: (filePath: string) => string | null; +export declare const tools: (target: string, options: IKBotTask) => Array; diff --git a/packages/kbot/dist-in/ai-tools/lib/tools/user.js b/packages/kbot/dist-in/ai-tools/lib/tools/user.js new file mode 100644 index 00000000..b52374d7 --- /dev/null +++ b/packages/kbot/dist-in/ai-tools/lib/tools/user.js @@ -0,0 +1,78 @@ +import { parse, join } from 'path'; +import * as fs from 'fs'; +import { lookup } from 'mime-types'; +import { toolLogger } from '../../index.js'; +export const mime = (file = '') => parse(file).ext ? lookup(file) : null; +//const screenshot = require('screenshot-desktop') +export const fileToBase64 = (filePath) => { + try { + const fileBuffer = fs.readFileSync(filePath); + const mimeType = lookup(filePath); + if (!mimeType) { + throw new Error('Unable to determine MIME type.'); + } + const base64Data = fileBuffer.toString('base64'); + return `data:${mimeType};base64,${base64Data}`; + } + catch (error) { + console.error('fileToBase64 : Error reading file:', error); + return null; + } +}; +export const tools = (target, options) => { + const logger = toolLogger('user', options); + return [ + { + type: 'function', + function: { + name: 'capture_screen', + description: 'Capture a screenshot and store it as file (jpg). Returns the path to the file', + parameters: { + type: 'object', + properties: { + file: { type: 'string' } + }, + required: ['file'] + }, + function: async (params) => { + try { + const outputPath = join(target, params.file); + const takeScreenshot = async () => { + /* + return new Promise((resolve, reject) => { + screenshot({ format: 'jpg' }).then((img) => { + write(outputPath, img) + resolve({ success: true, path: outputPath}) + }).catch(reject) + }) + */ + }; + const { path } = await takeScreenshot(); + return { + "role": "user", + "content": [ + /* + { + type: "image_url", + image_url: { + url: fileToBase64( path), + } + } + */ + ] + }; + } + catch (error) { + logger.error('Error capturing screenshot:', error); + return { + success: false, + error: error.message + }; + } + }, + parse: JSON.parse + } + } + ]; +}; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXNlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9haS10b29scy9saWIvdG9vbHMvdXNlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFDQSxPQUFPLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRSxNQUFNLE1BQU0sQ0FBQTtBQUdsQyxPQUFPLEtBQUssRUFBRSxNQUFNLElBQUksQ0FBQTtBQUN4QixPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sWUFBWSxDQUFBO0FBRW5DLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQTtBQUUzQyxNQUFNLENBQUMsTUFBTSxJQUFJLEdBQUcsQ0FBQyxPQUFlLEVBQUUsRUFBRSxFQUFFLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUE7QUFFaEYsa0RBQWtEO0FBRWxELE1BQU0sQ0FBQyxNQUFNLFlBQVksR0FBRyxDQUFDLFFBQWdCLEVBQWlCLEVBQUU7SUFDNUQsSUFBSSxDQUFDO1FBQ0QsTUFBTSxVQUFVLEdBQUcsRUFBRSxDQUFDLFlBQVksQ0FBQyxRQUFRLENBQUMsQ0FBQTtRQUM1QyxNQUFNLFFBQVEsR0FBRyxNQUFNLENBQUMsUUFBUSxDQUFDLENBQUE7UUFDakMsSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDO1lBQ1osTUFBTSxJQUFJLEtBQUssQ0FBQyxnQ0FBZ0MsQ0FBQyxDQUFBO1FBQ3JELENBQUM7UUFDRCxNQUFNLFVBQVUsR0FBRyxVQUFVLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxDQUFBO1FBQ2hELE9BQU8sUUFBUSxRQUFRLFdBQVcsVUFBVSxFQUFFLENBQUE7SUFDbEQsQ0FBQztJQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7UUFDYixPQUFPLENBQUMsS0FBSyxDQUFDLG9DQUFvQyxFQUFFLEtBQUssQ0FBQyxDQUFBO1FBQzFELE9BQU8sSUFBSSxDQUFBO0lBQ2YsQ0FBQztBQUNMLENBQUMsQ0FBQTtBQUNELE1BQU0sQ0FBQyxNQUFNLEtBQUssR0FBRyxDQUFDLE1BQWMsRUFBRSxPQUFrQixFQUFjLEVBQUU7SUFDcEUsTUFBTSxNQUFNLEdBQUcsVUFBVSxDQUFDLE1BQU0sRUFBRSxPQUFPLENBQUMsQ0FBQTtJQUMxQyxPQUFPO1FBQ0g7WUFDSSxJQUFJLEVBQUUsVUFBVTtZQUNoQixRQUFRLEVBQUU7Z0JBQ04sSUFBSSxFQUFFLGdCQUFnQjtnQkFDdEIsV0FBVyxFQUFFLCtFQUErRTtnQkFDNUYsVUFBVSxFQUFFO29CQUNSLElBQUksRUFBRSxRQUFRO29CQUNkLFVBQVUsRUFBRTt3QkFDUixJQUFJLEVBQUUsRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFO3FCQUMzQjtvQkFDRCxRQUFRLEVBQUUsQ0FBQyxNQUFNLENBQUM7aUJBQ3JCO2dCQUNELFFBQVEsRUFBRSxLQUFLLEVBQUUsTUFBVyxFQUFFLEVBQUU7b0JBQzVCLElBQUksQ0FBQzt3QkFDRCxNQUFNLFVBQVUsR0FBRyxJQUFJLENBQUMsTUFBTSxFQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQTt3QkFDNUMsTUFBTSxjQUFjLEdBQUcsS0FBSyxJQUFtQixFQUFFOzRCQUM3Qzs7Ozs7Ozs4QkFPRTt3QkFDTixDQUFDLENBQUE7d0JBQ0QsTUFBTSxFQUFFLElBQUksRUFBRSxHQUFHLE1BQU0sY0FBYyxFQUFFLENBQUE7d0JBQ3ZDLE9BQU87NEJBQ0gsTUFBTSxFQUFFLE1BQU07NEJBQ2QsU0FBUyxFQUNQOzRCQUNFOzs7Ozs7OzhCQU9FOzZCQUNIO3lCQUNKLENBQUE7b0JBQ1AsQ0FBQztvQkFBQyxPQUFPLEtBQVUsRUFBRSxDQUFDO3dCQUNsQixNQUFNLENBQUMsS0FBSyxDQUFDLDZCQUE2QixFQUFFLEtBQUssQ0FBQyxDQUFDO3dCQUNuRCxPQUFPOzRCQUNILE9BQU8sRUFBRSxLQUFLOzRCQUNkLEtBQUssRUFBRSxLQUFLLENBQUMsT0FBTzt5QkFDdkIsQ0FBQztvQkFDTixDQUFDO2dCQUNMLENBQUM7Z0JBQ0QsS0FBSyxFQUFFLElBQUksQ0FBQyxLQUFLO2FBQ3BCO1NBQ3lCO0tBQ2pDLENBQUM7QUFDTixDQUFDLENBQUMifQ== \ No newline at end of file diff --git a/packages/kbot/dist-in/ai-tools/types.d.ts b/packages/kbot/dist-in/ai-tools/types.d.ts new file mode 100644 index 00000000..0d181280 --- /dev/null +++ b/packages/kbot/dist-in/ai-tools/types.d.ts @@ -0,0 +1,24 @@ +import { ChatCompletion, ChatCompletionMessage, ChatCompletionMessageParam } from 'openai/resources'; +import { IKBotOptions } from './types_kbot.js'; +import OpenAI from 'openai'; +import { Logger, ILogObj } from 'tslog'; +import { RunnableFunctionWithParse } from 'openai/lib/RunnableFunction'; +export type onToolBefore = (ctx: RunnableFunctionWithParse, args: any) => Promise; +export type onToolAfter = (ctx: RunnableFunctionWithParse, args: any, result?: any) => Promise; +export interface ICollector { + onMessage: (message: ChatCompletionMessageParam) => void; + onToolCall: (tool: ChatCompletionMessage.FunctionCall) => void; + onFunctionCallResult: (content: string) => void; + onChatCompletion: (completion: ChatCompletion) => void; + onContent: (content: string) => void; + onTool: (category: string, name: string, args: any, result?: any) => void; + onToolBefore: onToolBefore; + onToolAfter: onToolAfter; +} +export interface IKBotTask extends IKBotOptions { + client?: OpenAI; + collector?: ICollector; + onRun?: (ctx: IKBotTask) => Promise; + logger?: Logger; + customTools?: any[]; +} diff --git a/packages/kbot/dist-in/ai-tools/types.js b/packages/kbot/dist-in/ai-tools/types.js new file mode 100644 index 00000000..546ee82e --- /dev/null +++ b/packages/kbot/dist-in/ai-tools/types.js @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvYWktdG9vbHMvdHlwZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IiJ9 \ No newline at end of file diff --git a/packages/kbot/dist-in/ai-tools/types_kbot.d.ts b/packages/kbot/dist-in/ai-tools/types_kbot.d.ts new file mode 100644 index 00000000..e7951110 --- /dev/null +++ b/packages/kbot/dist-in/ai-tools/types_kbot.d.ts @@ -0,0 +1,569 @@ +export interface IKBotOptions { + /** Target directory */ + path?: string; + /** The prompt. Supports file paths and environment variables. */ + prompt?: string | undefined; + /** Optional output path for modified files (Tool mode only) */ + output?: string | undefined; + /** Optional destination path for the result, will substitute ${MODEL_NAME} and ${ROUTER} in the path. Optional, used for "completion" mode */ + dst?: string | undefined; + /** How to handle output if --dst file already exists: "concat" (append) or "merge" (try to merge structures if possible, otherwise append). Only used if --dst is specified. */ + append?: ("concat" | "merge" | "replace") | undefined; + /** Specify how to wrap the output, "meta (file name, absolute path, cwd)" or "none". */ + wrap?: "meta" | "none"; + /** Iterate over items, supported: GLOB | Path to JSON File | array of strings (comma separated). To test different models, use --each="gpt-3.5-turbo,gpt-4o", the actual string will exposed as variable `ITEM`, eg: --dst="${ITEM}-output.md" */ + each?: string | undefined; + /** Disable tools categories, eg: --disable=fs,git,interact,terminal,search,web,email,user */ + disable?: string[]; + /** List of specific tools to disable */ + disableTools?: string[]; + /** List of tools to use. Can be built-in tool names or paths to custom tool files. Default: fs,git,interact,terminal,search,web,email,user */ + tools?: (string[] | string); + /** Comma separated glob patterns or paths, eg --include=src/*.tsx,src/*.ts --include=package.json */ + include?: string[] | undefined; + /** Comma separated glob patterns or paths, eg --exclude=src/*.tsx,src/*.ts --exclude=package.json */ + exclude?: string[] | undefined; + /** Specify a glob extension behavior. Available presets: match-cpp. Also accepts a custom glob pattern with variables like ${SRC_DIR}, ${SRC_NAME}, ${SRC_EXT}. E.g., "match-cpp" or "${SRC_DIR}/${SRC_NAME}*.cpp" */ + globExtension?: (("match-cpp") | string) | undefined; + /** Explicit API key to use */ + api_key?: string | undefined; + /** AI model to use for processing. Available models: +  +  OpenRouter models: +  + ai21/jamba-large-1.7 | paid + aion-labs/aion-1.0 | paid + aion-labs/aion-1.0-mini | paid + aion-labs/aion-2.0 | paid + aion-labs/aion-rp-llama-3.1-8b | paid + alfredpros/codellama-7b-instruct-solidity | paid + allenai/molmo-2-8b | paid + allenai/olmo-2-0325-32b-instruct | paid + allenai/olmo-3-32b-think | paid + allenai/olmo-3-7b-instruct | paid + allenai/olmo-3-7b-think | paid + allenai/olmo-3.1-32b-instruct | paid + allenai/olmo-3.1-32b-think | paid + amazon/nova-2-lite-v1 | paid + amazon/nova-lite-v1 | paid + amazon/nova-micro-v1 | paid + amazon/nova-premier-v1 | paid + amazon/nova-pro-v1 | paid + anthropic/claude-3-haiku | paid + anthropic/claude-3.5-haiku | paid + anthropic/claude-3.5-sonnet | paid + anthropic/claude-3.7-sonnet | paid + anthropic/claude-3.7-sonnet:thinking | paid + anthropic/claude-haiku-4.5 | paid + anthropic/claude-opus-4 | paid + anthropic/claude-opus-4.1 | paid + anthropic/claude-opus-4.5 | paid + anthropic/claude-opus-4.6 | paid + anthropic/claude-sonnet-4 | paid + anthropic/claude-sonnet-4.5 | paid + anthropic/claude-sonnet-4.6 | paid + arcee-ai/coder-large | paid + arcee-ai/maestro-reasoning | paid + arcee-ai/spotlight | paid + arcee-ai/trinity-large-preview:free | free + arcee-ai/trinity-mini | paid + arcee-ai/trinity-mini:free | free + arcee-ai/virtuoso-large | paid + openrouter/auto | paid + baidu/ernie-4.5-21b-a3b | paid + baidu/ernie-4.5-21b-a3b-thinking | paid + baidu/ernie-4.5-300b-a47b | paid + baidu/ernie-4.5-vl-28b-a3b | paid + baidu/ernie-4.5-vl-424b-a47b | paid + openrouter/bodybuilder | paid + bytedance-seed/seed-1.6 | paid + bytedance-seed/seed-1.6-flash | paid + bytedance-seed/seed-2.0-lite | paid + bytedance-seed/seed-2.0-mini | paid + bytedance/ui-tars-1.5-7b | paid + cohere/command-a | paid + cohere/command-r-08-2024 | paid + cohere/command-r-plus-08-2024 | paid + cohere/command-r7b-12-2024 | paid + deepcogito/cogito-v2.1-671b | paid + deepseek/deepseek-chat | paid + deepseek/deepseek-chat-v3-0324 | paid + deepseek/deepseek-chat-v3.1 | paid + deepseek/deepseek-v3.1-terminus | paid + deepseek/deepseek-v3.2 | paid + deepseek/deepseek-v3.2-exp | paid + deepseek/deepseek-v3.2-speciale | paid + deepseek/deepseek-r1 | paid + deepseek/deepseek-r1-0528 | paid + deepseek/deepseek-r1-distill-llama-70b | paid + deepseek/deepseek-r1-distill-qwen-32b | paid + eleutherai/llemma_7b | paid + essentialai/rnj-1-instruct | paid + openrouter/free | paid + alpindale/goliath-120b | paid + google/gemini-2.0-flash-001 | paid + google/gemini-2.0-flash-lite-001 | paid + google/gemini-2.5-flash | paid + google/gemini-2.5-flash-lite | paid + google/gemini-2.5-flash-lite-preview-09-2025 | paid + google/gemini-2.5-pro | paid + google/gemini-2.5-pro-preview-05-06 | paid + google/gemini-2.5-pro-preview | paid + google/gemini-3-flash-preview | paid + google/gemini-3-pro-preview | paid + google/gemini-3.1-flash-lite-preview | paid + google/gemini-3.1-pro-preview | paid + google/gemini-3.1-pro-preview-customtools | paid + google/gemma-2-27b-it | paid + google/gemma-2-9b-it | paid + google/gemma-3-12b-it | paid + google/gemma-3-12b-it:free | free + google/gemma-3-27b-it | paid + google/gemma-3-27b-it:free | free + google/gemma-3-4b-it | paid + google/gemma-3-4b-it:free | free + google/gemma-3n-e2b-it:free | free + google/gemma-3n-e4b-it | paid + google/gemma-3n-e4b-it:free | free + google/gemini-2.5-flash-image | paid + google/gemini-3.1-flash-image-preview | paid + google/gemini-3-pro-image-preview | paid + ibm-granite/granite-4.0-h-micro | paid + inception/mercury | paid + inception/mercury-2 | paid + inception/mercury-coder | paid + inflection/inflection-3-pi | paid + inflection/inflection-3-productivity | paid + kwaipilot/kat-coder-pro | paid + liquid/lfm-2.2-6b | paid + liquid/lfm-2-24b-a2b | paid + liquid/lfm2-8b-a1b | paid + liquid/lfm-2.5-1.2b-instruct:free | free + liquid/lfm-2.5-1.2b-thinking:free | free + meta-llama/llama-guard-3-8b | paid + anthracite-org/magnum-v4-72b | paid + mancer/weaver | paid + meituan/longcat-flash-chat | paid + meta-llama/llama-3-70b-instruct | paid + meta-llama/llama-3-8b-instruct | paid + meta-llama/llama-3.1-405b | paid + meta-llama/llama-3.1-70b-instruct | paid + meta-llama/llama-3.1-8b-instruct | paid + meta-llama/llama-3.2-11b-vision-instruct | paid + meta-llama/llama-3.2-1b-instruct | paid + meta-llama/llama-3.2-3b-instruct | paid + meta-llama/llama-3.2-3b-instruct:free | free + meta-llama/llama-3.3-70b-instruct | paid + meta-llama/llama-3.3-70b-instruct:free | free + meta-llama/llama-4-maverick | paid + meta-llama/llama-4-scout | paid + meta-llama/llama-guard-4-12b | paid + microsoft/phi-4 | paid + minimax/minimax-m1 | paid + minimax/minimax-m2 | paid + minimax/minimax-m2-her | paid + minimax/minimax-m2.1 | paid + minimax/minimax-m2.5 | paid + minimax/minimax-m2.5:free | free + minimax/minimax-m2.7 | paid + minimax/minimax-01 | paid + mistralai/mistral-large | paid + mistralai/mistral-large-2407 | paid + mistralai/mistral-large-2411 | paid + mistralai/codestral-2508 | paid + mistralai/devstral-2512 | paid + mistralai/devstral-medium | paid + mistralai/devstral-small | paid + mistralai/ministral-14b-2512 | paid + mistralai/ministral-3b-2512 | paid + mistralai/ministral-8b-2512 | paid + mistralai/mistral-7b-instruct-v0.1 | paid + mistralai/mistral-large-2512 | paid + mistralai/mistral-medium-3 | paid + mistralai/mistral-medium-3.1 | paid + mistralai/mistral-nemo | paid + mistralai/mistral-small-24b-instruct-2501 | paid + mistralai/mistral-small-3.1-24b-instruct | paid + mistralai/mistral-small-3.1-24b-instruct:free | free + mistralai/mistral-small-3.2-24b-instruct | paid + mistralai/mistral-small-2603 | paid + mistralai/mistral-small-creative | paid + mistralai/mixtral-8x22b-instruct | paid + mistralai/mixtral-8x7b-instruct | paid + mistralai/pixtral-large-2411 | paid + mistralai/mistral-saba | paid + mistralai/voxtral-small-24b-2507 | paid + moonshotai/kimi-k2 | paid + moonshotai/kimi-k2-0905 | paid + moonshotai/kimi-k2-thinking | paid + moonshotai/kimi-k2.5 | paid + morph/morph-v3-fast | paid + morph/morph-v3-large | paid + gryphe/mythomax-l2-13b | paid + nex-agi/deepseek-v3.1-nex-n1 | paid + nousresearch/hermes-3-llama-3.1-405b | paid + nousresearch/hermes-3-llama-3.1-405b:free | free + nousresearch/hermes-3-llama-3.1-70b | paid + nousresearch/hermes-4-405b | paid + nousresearch/hermes-4-70b | paid + nousresearch/hermes-2-pro-llama-3-8b | paid + nvidia/llama-3.1-nemotron-70b-instruct | paid + nvidia/llama-3.3-nemotron-super-49b-v1.5 | paid + nvidia/nemotron-3-nano-30b-a3b | paid + nvidia/nemotron-3-nano-30b-a3b:free | free + nvidia/nemotron-3-super-120b-a12b | paid + nvidia/nemotron-3-super-120b-a12b:free | free + nvidia/nemotron-nano-12b-v2-vl | paid + nvidia/nemotron-nano-12b-v2-vl:free | free + nvidia/nemotron-nano-9b-v2 | paid + nvidia/nemotron-nano-9b-v2:free | free + openai/gpt-audio | paid + openai/gpt-audio-mini | paid + openai/gpt-3.5-turbo | paid + openai/gpt-3.5-turbo-0613 | paid + openai/gpt-3.5-turbo-16k | paid + openai/gpt-3.5-turbo-instruct | paid + openai/gpt-4 | paid + openai/gpt-4-0314 | paid + openai/gpt-4-turbo | paid + openai/gpt-4-1106-preview | paid + openai/gpt-4-turbo-preview | paid + openai/gpt-4.1 | paid + openai/gpt-4.1-mini | paid + openai/gpt-4.1-nano | paid + openai/gpt-4o | paid + openai/gpt-4o-2024-05-13 | paid + openai/gpt-4o-2024-08-06 | paid + openai/gpt-4o-2024-11-20 | paid + openai/gpt-4o:extended | paid + openai/gpt-4o-audio-preview | paid + openai/gpt-4o-search-preview | paid + openai/gpt-4o-mini | paid + openai/gpt-4o-mini-2024-07-18 | paid + openai/gpt-4o-mini-search-preview | paid + openai/gpt-5 | paid + openai/gpt-5-chat | paid + openai/gpt-5-codex | paid + openai/gpt-5-image | paid + openai/gpt-5-image-mini | paid + openai/gpt-5-mini | paid + openai/gpt-5-nano | paid + openai/gpt-5-pro | paid + openai/gpt-5.1 | paid + openai/gpt-5.1-chat | paid + openai/gpt-5.1-codex | paid + openai/gpt-5.1-codex-max | paid + openai/gpt-5.1-codex-mini | paid + openai/gpt-5.2 | paid + openai/gpt-5.2-chat | paid + openai/gpt-5.2-pro | paid + openai/gpt-5.2-codex | paid + openai/gpt-5.3-chat | paid + openai/gpt-5.3-codex | paid + openai/gpt-5.4 | paid + openai/gpt-5.4-mini | paid + openai/gpt-5.4-nano | paid + openai/gpt-5.4-pro | paid + openai/gpt-oss-120b | paid + openai/gpt-oss-120b:free | free + openai/gpt-oss-20b | paid + openai/gpt-oss-20b:free | free + openai/gpt-oss-safeguard-20b | paid + openai/o1 | paid + openai/o1-pro | paid + openai/o3 | paid + openai/o3-deep-research | paid + openai/o3-mini | paid + openai/o3-mini-high | paid + openai/o3-pro | paid + openai/o4-mini | paid + openai/o4-mini-deep-research | paid + openai/o4-mini-high | paid + perplexity/sonar | paid + perplexity/sonar-deep-research | paid + perplexity/sonar-pro | paid + perplexity/sonar-pro-search | paid + perplexity/sonar-reasoning-pro | paid + prime-intellect/intellect-3 | paid + qwen/qwen-plus-2025-07-28 | paid + qwen/qwen-plus-2025-07-28:thinking | paid + qwen/qwen-vl-max | paid + qwen/qwen-vl-plus | paid + qwen/qwen-max | paid + qwen/qwen-plus | paid + qwen/qwen-turbo | paid + qwen/qwen-2.5-7b-instruct | paid + qwen/qwen2.5-coder-7b-instruct | paid + qwen/qwen2.5-vl-32b-instruct | paid + qwen/qwen2.5-vl-72b-instruct | paid + qwen/qwen-2.5-vl-7b-instruct | paid + qwen/qwen3-14b | paid + qwen/qwen3-235b-a22b | paid + qwen/qwen3-235b-a22b-2507 | paid + qwen/qwen3-235b-a22b-thinking-2507 | paid + qwen/qwen3-30b-a3b | paid + qwen/qwen3-30b-a3b-instruct-2507 | paid + qwen/qwen3-30b-a3b-thinking-2507 | paid + qwen/qwen3-32b | paid + qwen/qwen3-4b:free | free + qwen/qwen3-8b | paid + qwen/qwen3-coder-30b-a3b-instruct | paid + qwen/qwen3-coder | paid + qwen/qwen3-coder:free | free + qwen/qwen3-coder-flash | paid + qwen/qwen3-coder-next | paid + qwen/qwen3-coder-plus | paid + qwen/qwen3-max | paid + qwen/qwen3-max-thinking | paid + qwen/qwen3-next-80b-a3b-instruct | paid + qwen/qwen3-next-80b-a3b-instruct:free | free + qwen/qwen3-next-80b-a3b-thinking | paid + qwen/qwen3-vl-235b-a22b-instruct | paid + qwen/qwen3-vl-235b-a22b-thinking | paid + qwen/qwen3-vl-30b-a3b-instruct | paid + qwen/qwen3-vl-30b-a3b-thinking | paid + qwen/qwen3-vl-32b-instruct | paid + qwen/qwen3-vl-8b-instruct | paid + qwen/qwen3-vl-8b-thinking | paid + qwen/qwen3.5-397b-a17b | paid + qwen/qwen3.5-plus-02-15 | paid + qwen/qwen3.5-122b-a10b | paid + qwen/qwen3.5-27b | paid + qwen/qwen3.5-35b-a3b | paid + qwen/qwen3.5-9b | paid + qwen/qwen3.5-flash-02-23 | paid + qwen/qwq-32b | paid + qwen/qwen-2.5-72b-instruct | paid + qwen/qwen-2.5-coder-32b-instruct | paid + relace/relace-apply-3 | paid + relace/relace-search | paid + undi95/remm-slerp-l2-13b | paid + sao10k/l3-lunaris-8b | paid + sao10k/l3-euryale-70b | paid + sao10k/l3.1-70b-hanami-x1 | paid + sao10k/l3.1-euryale-70b | paid + sao10k/l3.3-euryale-70b | paid + stepfun/step-3.5-flash | paid + stepfun/step-3.5-flash:free | free + switchpoint/router | paid + tencent/hunyuan-a13b-instruct | paid + thedrummer/cydonia-24b-v4.1 | paid + thedrummer/rocinante-12b | paid + thedrummer/skyfall-36b-v2 | paid + thedrummer/unslopnemo-12b | paid + tngtech/deepseek-r1t2-chimera | paid + alibaba/tongyi-deepresearch-30b-a3b | paid + upstage/solar-pro-3 | paid + cognitivecomputations/dolphin-mistral-24b-venice-edition:free | free + microsoft/wizardlm-2-8x22b | paid + writer/palmyra-x5 | paid + x-ai/grok-3 | paid + x-ai/grok-3-beta | paid + x-ai/grok-3-mini | paid + x-ai/grok-3-mini-beta | paid + x-ai/grok-4 | paid + x-ai/grok-4-fast | paid + x-ai/grok-4.1-fast | paid + x-ai/grok-4.20-beta | paid + x-ai/grok-4.20-multi-agent-beta | paid + x-ai/grok-code-fast-1 | paid + xiaomi/mimo-v2-flash | paid + xiaomi/mimo-v2-omni | paid + xiaomi/mimo-v2-pro | paid + z-ai/glm-4-32b | paid + z-ai/glm-4.5 | paid + z-ai/glm-4.5-air | paid + z-ai/glm-4.5-air:free | free + z-ai/glm-4.5v | paid + z-ai/glm-4.6 | paid + z-ai/glm-4.6v | paid + z-ai/glm-4.7 | paid + z-ai/glm-4.7-flash | paid + z-ai/glm-5 | paid + z-ai/glm-5-turbo | paid +  +  OpenAI models: +  + babbage-002 + chatgpt-image-latest + dall-e-2 + dall-e-3 + davinci-002 + gpt-3.5-turbo + gpt-3.5-turbo-0125 + gpt-3.5-turbo-1106 + gpt-3.5-turbo-16k + gpt-3.5-turbo-instruct + gpt-3.5-turbo-instruct-0914 + gpt-4 + gpt-4-0125-preview + gpt-4-0613 + gpt-4-1106-preview + gpt-4-turbo + gpt-4-turbo-2024-04-09 + gpt-4-turbo-preview + gpt-4.1 + gpt-4.1-2025-04-14 + gpt-4.1-mini + gpt-4.1-mini-2025-04-14 + gpt-4.1-nano + gpt-4.1-nano-2025-04-14 + gpt-4o + gpt-4o-2024-05-13 + gpt-4o-2024-08-06 + gpt-4o-2024-11-20 + gpt-4o-audio-preview + gpt-4o-audio-preview-2024-12-17 + gpt-4o-audio-preview-2025-06-03 + gpt-4o-mini + gpt-4o-mini-2024-07-18 + gpt-4o-mini-audio-preview + gpt-4o-mini-audio-preview-2024-12-17 + gpt-4o-mini-realtime-preview + gpt-4o-mini-realtime-preview-2024-12-17 + gpt-4o-mini-search-preview + gpt-4o-mini-search-preview-2025-03-11 + gpt-4o-mini-transcribe + gpt-4o-mini-transcribe-2025-03-20 + gpt-4o-mini-transcribe-2025-12-15 + gpt-4o-mini-tts + gpt-4o-mini-tts-2025-03-20 + gpt-4o-mini-tts-2025-12-15 + gpt-4o-realtime-preview + gpt-4o-realtime-preview-2024-12-17 + gpt-4o-realtime-preview-2025-06-03 + gpt-4o-search-preview + gpt-4o-search-preview-2025-03-11 + gpt-4o-transcribe + gpt-4o-transcribe-diarize + gpt-5 + gpt-5-2025-08-07 + gpt-5-chat-latest + gpt-5-codex + gpt-5-mini + gpt-5-mini-2025-08-07 + gpt-5-nano + gpt-5-nano-2025-08-07 + gpt-5-pro + gpt-5-pro-2025-10-06 + gpt-5-search-api + gpt-5-search-api-2025-10-14 + gpt-5.1 + gpt-5.1-2025-11-13 + gpt-5.1-chat-latest + gpt-5.1-codex + gpt-5.1-codex-max + gpt-5.1-codex-mini + gpt-5.2 + gpt-5.2-2025-12-11 + gpt-5.2-chat-latest + gpt-5.2-codex + gpt-5.2-pro + gpt-5.2-pro-2025-12-11 + gpt-5.3-chat-latest + gpt-5.3-codex + gpt-5.4 + gpt-5.4-2026-03-05 + gpt-5.4-mini + gpt-5.4-mini-2026-03-17 + gpt-5.4-nano + gpt-5.4-nano-2026-03-17 + gpt-5.4-pro + gpt-5.4-pro-2026-03-05 + gpt-audio + gpt-audio-1.5 + gpt-audio-2025-08-28 + gpt-audio-mini + gpt-audio-mini-2025-10-06 + gpt-audio-mini-2025-12-15 + gpt-image-1 + gpt-image-1-mini + gpt-image-1.5 + gpt-realtime + gpt-realtime-1.5 + gpt-realtime-2025-08-28 + gpt-realtime-mini + gpt-realtime-mini-2025-10-06 + gpt-realtime-mini-2025-12-15 + o1 + o1-2024-12-17 + o1-pro + o1-pro-2025-03-19 + o3 + o3-2025-04-16 + o3-mini + o3-mini-2025-01-31 + o4-mini + o4-mini-2025-04-16 + o4-mini-deep-research + o4-mini-deep-research-2025-06-26 + omni-moderation-2024-09-26 + omni-moderation-latest + sora-2 + sora-2-pro + text-embedding-3-large + text-embedding-3-small + text-embedding-ada-002 + tts-1 + tts-1-1106 + tts-1-hd + tts-1-hd-1106 + whisper-1 + ----- + +  +  Deepseek models: +  + deepseek-chat + deepseek-reasoner + ----- + */ + model?: string | undefined; + /** Router to use: openai, openrouter or deepseek */ + router?: string; + /** Chat completion mode: + completion, tools, assistant. + completion: no support for tools, please use --dst parameter to save the output. + tools: allows for tools to be used, eg 'save to ./output.md'. Not all models support this mode. + responses: allows for responses to be used, eg 'save to ./output.md'. Not all models support this mode. + assistant: : allows documents (PDF, DOCX, ...) to be added but dont support tools. Use --dst to save the output. Supported files : + custom: custom mode + */ + mode?: "completion" | "tools" | "assistant" | "responses" | "custom"; + /** Logging level for the application */ + logLevel?: number; + /** Path to profile for variables. Supports environment variables. */ + profile?: string | undefined; + /** Base URL for the API, set via --router or directly */ + baseURL?: string | undefined; + /** Path to JSON configuration file (API keys). Supports environment variables. */ + config?: string | undefined; + /** Create a script */ + dump?: string | undefined; + /** Path to preferences file, eg: location, your email address, gender, etc. Supports environment variables. */ + preferences?: string; + /** Logging directory */ + logs?: string; + /** Enable streaming (verbose LLM output) */ + stream?: boolean; + /** Use alternate tokenizer & instead of $ */ + alt?: boolean; + /** Environment (in profile) */ + env?: string; + variables?: { + [x: string]: string; + }; + /** List of filters to apply to the output. + Used only in completion mode and a given output file specified with --dst. + It unwraps by default any code or data in Markdown. + Choices: + JSON,JSONUnescape,JSONPretty,AlphaSort,code,JSONParse,trim,markdown + */ + filters?: (string | ("JSON" | "JSONUnescape" | "JSONPretty" | "AlphaSort" | "code" | "JSONParse" | "trim" | "markdown")[] | string[] | ((...args_0: unknown[]) => unknown)[]); + /** JSONPath query to be used to transform input objects */ + query?: (string | null); + /** Dry run - only write out parameters without making API calls */ + dry?: (boolean | string); + /** Format for structured outputs. Can be a Zod schema, a Zod schema string, a JSON schema string, or a path to a JSON file. */ + format?: (string | any) | undefined; +} diff --git a/packages/kbot/dist-in/ai-tools/types_kbot.js b/packages/kbot/dist-in/ai-tools/types_kbot.js new file mode 100644 index 00000000..602c950f --- /dev/null +++ b/packages/kbot/dist-in/ai-tools/types_kbot.js @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXNfa2JvdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9haS10b29scy90eXBlc19rYm90LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiIifQ== \ No newline at end of file diff --git a/packages/kbot/dist/package.json b/packages/kbot/dist/package.json new file mode 100644 index 00000000..660d8e87 --- /dev/null +++ b/packages/kbot/dist/package.json @@ -0,0 +1,20 @@ +{ + "name": "@plastichub/kbot", + "version": "1.3.0", + "main": "main_node.js", + "author": "", + "license": "ISC", + "description": "", + "bin": { + "kbot": "./main_node.js" + }, + "dependencies": { + "node-emoji": "^2.2.0" + }, + "publishConfig": { + "access": "public" + }, + "optionalDependencies": { + "puppeteer": "^23.11.1" + } +} \ No newline at end of file diff --git a/packages/kbot/src/ai-tools/.gitignore b/packages/kbot/src/ai-tools/.gitignore new file mode 100644 index 00000000..e69de29b diff --git a/packages/kbot/src/ai-tools/commands/index.ts b/packages/kbot/src/ai-tools/commands/index.ts new file mode 100644 index 00000000..c466db02 --- /dev/null +++ b/packages/kbot/src/ai-tools/commands/index.ts @@ -0,0 +1,27 @@ +import type { Argv } from 'yargs' +import { types } from './types.js' +import { list, options as listOptions } from './list.js' +import { invoke, invokeOptions } from './invoke.js' +import { CONFIG_DEFAULT } from '@polymech/commons' +import { logger } from '../index.js' + +export const commands = (yargs: Argv) => { + return yargs + .command('types', 'Generate TypeScript interfaces from Zod schemas', {}, types) + .command('list', 'List all available tools and their descriptions', listOptions, list) + .command('invoke', 'Invoke a specific tool function', invokeOptions, invoke) + .option('env_key', { + type: 'string', + description: 'Environment configuration key' + }) + .middleware([(argv) => { + const config = CONFIG_DEFAULT(argv.env_key) as any; + if (!config) { + logger.warn('No config found!'); + return; + } + return config; + }]) + .strict() + .help(); +}; \ No newline at end of file diff --git a/packages/kbot/src/ai-tools/commands/invoke.ts b/packages/kbot/src/ai-tools/commands/invoke.ts new file mode 100644 index 00000000..30573096 --- /dev/null +++ b/packages/kbot/src/ai-tools/commands/invoke.ts @@ -0,0 +1,55 @@ +import { tools } from '../lib/tools/tools.js' +import { logger } from '../index.js' +import { InvokeToolSchema } from '../zod_schemas.js' +import { toYargs } from '@polymech/commons/schemas' +import { sync as write } from '@polymech/fs/write' +import type { Argv } from 'yargs' +import * as path from 'path' + +const options = (yargs: Argv) => toYargs(yargs, InvokeToolSchema); + +export const invoke = async (argv: any) => { + try { + const { tools: toolCategory, function: funcName, target, params, output } = argv; + + // Get tool category + const toolSet = tools[toolCategory]; + if (!toolSet) { + logger.error(`Tool category '${toolCategory}' not found`); + return; + } + + // Initialize tools with target directory + const toolList = toolSet(target); + + // Find specific function + const tool = toolList.find(t => t.function.name === funcName); + if (!tool) { + logger.error(`Function '${funcName}' not found in ${toolCategory} tools`); + return; + } + + // Parse parameters if provided + const parameters = params ? JSON.parse(params) : {}; + + // Execute tool function + logger.info(`Invoking ${toolCategory}::${funcName}`); + const result = await tool.function.function(parameters); + + // Handle output + if (output) { + const outputPath = path.isAbsolute(output) ? output : path.join(process.cwd(), output); + logger.info(`Writing output to ${outputPath}`); + write(outputPath, JSON.stringify(result, null, 2)); + } else { + logger.info('Result:', result); + } + + return result; + } catch (error) { + logger.error('Error invoking tool:', error); + throw error; + } +}; + +export { options as invokeOptions }; \ No newline at end of file diff --git a/packages/kbot/src/ai-tools/commands/list.ts b/packages/kbot/src/ai-tools/commands/list.ts new file mode 100644 index 00000000..7a394519 --- /dev/null +++ b/packages/kbot/src/ai-tools/commands/list.ts @@ -0,0 +1,75 @@ +import type { Argv } from 'yargs' +import { tools } from '../lib/tools/tools.js' +import { logger } from '../index.js' +import { ListCommandSchema } from '../zod_schemas.js' +import { sync as write } from '@polymech/fs/write' +import { toYargs } from '@polymech/commons/schemas' + +export const options = (yargs: Argv) => toYargs(yargs, ListCommandSchema) + +interface FSParameters { + type: string; + properties: Record; + required: string[]; +} +interface FSDefinition { + name: string; + description: string; + category: string; + parameters: FSParameters; +} +interface FSData { + fs: FSDefinition[]; +} + +export const signature = (definition: FSDefinition): string => { + const { properties } = definition.parameters; + const requiredKeys = definition.parameters.required || []; + const params = Object.entries(properties).map(([key, val]) => { + const isRequired = requiredKeys.includes(key); + const isOptional = !!val.optional || !isRequired; + return isOptional ? `?${key}` : key; + }); + return `(${params.join(", ")})`; +} + +export function format(category: string, data: any): string { + const lines: string[] = [`## ${category}\n`]; + data.forEach(definition => { + const functionName = definition.name + const args = `${signature(definition)}` + const summary = definition.description + lines.push(`- ${functionName}${args}: ${summary}`) + }) + return lines.join("\n") +} + +export const list = async (argv: any, options?: any) => { + const getCategorizedTools = (category, options) => { + const toolsArray = tools[category](process.cwd(), options); + return toolsArray.map(tool => ({ + name: tool.function.name, + description: tool.function.description, + category, + parameters: tool.function.parameters + })); + } + const toolsList = { + email: getCategorizedTools('email', options), + search: getCategorizedTools('search', options), + interact: getCategorizedTools('email', options), + fs: getCategorizedTools('fs', options), + npm: getCategorizedTools('npm', options), + git: getCategorizedTools('git', options), + terminal: getCategorizedTools('terminal', options) + } + //write(argv.output + '.json', Object.keys(toolsList).map((k,v)=>format(k,v as any)).join('\n') ); + + const shortDescription = Object.keys(toolsList).map((value:string) => { + return format(value,toolsList[value]) + }).join('\n\n'); + if (argv.output) { + write(argv.output, JSON.stringify(toolsList, null, 2)) + write(argv.output + '.md', shortDescription) + } +} \ No newline at end of file diff --git a/packages/kbot/src/ai-tools/commands/types.ts b/packages/kbot/src/ai-tools/commands/types.ts new file mode 100644 index 00000000..b8a5a708 --- /dev/null +++ b/packages/kbot/src/ai-tools/commands/types.ts @@ -0,0 +1,29 @@ +import { generate_interfaces } from '@polymech/commons' + +import { + FileListingOptionsSchema, + FileRemovalOptionsSchema, + GitCommitSchema, + GitRevertSchema, + GitSwitchVersionSchema, + InvokeToolSchema, + ToolListingOptionsSchema, + TerminalCommandSchema, + ListCommandSchema, + NpmRunSchema +} from '../zod_schemas.js' + +export const types = async () => { + return generate_interfaces([ + FileListingOptionsSchema, + FileRemovalOptionsSchema, + GitCommitSchema, + GitRevertSchema, + GitSwitchVersionSchema, + InvokeToolSchema, + ToolListingOptionsSchema, + TerminalCommandSchema, + ListCommandSchema, + NpmRunSchema + ], 'src/zod_types.ts') +} \ No newline at end of file diff --git a/packages/kbot/src/ai-tools/constants.ts b/packages/kbot/src/ai-tools/constants.ts new file mode 100644 index 00000000..656de06d --- /dev/null +++ b/packages/kbot/src/ai-tools/constants.ts @@ -0,0 +1,11 @@ +export const LOGGER_NAME = 'llm-tools-cli' + +export const EXCLUDE_GLOB = [ + "**/node_modules/**", + "**/dist/**", + "**/build/**", + "**/coverage/**", + "*.log", + ".kbot", + ".git" +] \ No newline at end of file diff --git a/packages/kbot/src/ai-tools/index.ts b/packages/kbot/src/ai-tools/index.ts new file mode 100644 index 00000000..a2dbf15a --- /dev/null +++ b/packages/kbot/src/ai-tools/index.ts @@ -0,0 +1,186 @@ +import * as path from 'path' +import { z } from 'zod' + +import { ISettingsParam, Logger } from "tslog" + +import * as winston from 'winston' +import TransportStream from 'winston-transport' +import { SeqTransport} from '@datalust/winston-seq' +import { createStream } from "rotating-file-stream" + +import { CONFIG_DEFAULT } from '@polymech/commons' +import { sync as read } from '@polymech/fs/read' +import { sync as write } from '@polymech/fs/write' +import { sync as exists } from '@polymech/fs/exists' + +import { IKBotTask } from './types.js' + +export let logger: Logger = createLogger('osr-ai-tools') +export const TLogLevelNameSchema = z.enum(["silly", "trace", "debug", "info", "warn", "error", "fatal"]) +export type LogLevel = z.infer +export enum LogLevelEx { + silly, + trace, + debug, + info, + warn, + error, + fatal +} +export enum ELogTargets { + Console = 1 << 0, + FileText = 1 << 1, + FileJson = 1 << 2, + Seq = 1 << 3 +} +export function createLogger(name: string, options?: ISettingsParam) { + return new Logger({ + name, + type: 'pretty', + ...options, + }) +} +export const defaultLogger = createLogger('DefaultLogger', { + minLevel: LogLevelEx.info +}) + +class JsonArrayFileTransport extends TransportStream { + filename: string; + constructor(opts) { + super(opts); + opts.filename = opts.filename + this.filename = opts.filename || 'logs.json'; + setImmediate(() => this.emit('opened')) + } + log(info: any, next: () => void): void { + setImmediate(() => this.emit('logged', info)) + const { level, message, exception, stack, ...props } = info; + const fileExists = exists(this.filename) + const existingLogs = fileExists + ? read(this.filename, 'json') as [] + : []; + + const entry = { + level: info.level, + message: info.message, + timestamp: new Date().toISOString(), + ...info + }; + existingLogs.push(entry) + write(this.filename, existingLogs) + next() + } + close(): void { + setImmediate(() => this.emit('closed')) + } + flush(): Promise { + return new Promise((resolve, reject) => { + resolve(true) + }) + } +} + +class TSLogTransport extends TransportStream { + constructor(opts) { + super(opts); + setImmediate(() => this.emit('opened')) + } + log(info: any, next: () => void): void { + setImmediate(() => this.emit('logged', info)) + const { level, message, exception, stack, ...props } = info; + defaultLogger.info(info) + next() + } +} + +export const winstonLogger = (name: string, file: string, targets: ELogTargets = ELogTargets.Console | ELogTargets.FileJson) => { + const logger = winston.createLogger({ + defaultMeta: { service: name }, + level: 'debug', + transports: [] + }) + if (targets & ELogTargets.Console) { + //logger.add(new TSLogTransport({})) + logger.add(new winston.transports.Console({ + format: winston.format.combine( + winston.format.timestamp({ format: 'MM/DD/YYYY hh:mm:ss.SSS' }), + ///winston.format.json(), + winston.format.colorize(), + winston.format.printf(info => { + let message = null + try { + message = JSON.stringify(info.message) + } catch (e) { + + } + return `[${info.level}] [${name}] | message: ${message.substring(0, 200)}` + })) + })) + } + + if (targets & ELogTargets.FileText) { + logger.add(new winston.transports.File({ + format: winston.format.combine( + winston.format.timestamp(), + winston.format.timestamp({ format: 'MM/DD/YYYY hh:mm:ss.SSS' }), + winston.format.json(), + winston.format.printf(info => { + return JSON.stringify(info, null, 2); + })), + dirname: path.parse(file).dir, + filename: path.parse(file).base + })) + } + + if (targets & ELogTargets.FileJson) { + logger.add(new JsonArrayFileTransport({ + filename: file + })) + } + + if (targets & ELogTargets.Seq) { + const config = CONFIG_DEFAULT() as any + if (config.seq) { + logger.add(new SeqTransport({ + ...config.seq, + onError: (e => { }) + })) + } + } + return logger +} + +export const createFileLogger = (logger: Logger, level: number, file: string): Logger => { + const rfs = createStream(file, + { + size: "10M", // rotate every 10 MegaBytes written + interval: "1d", // rotate daily + compress: "gzip", // compress rotated files + }); + + const log = new Logger({ + type: "json", + attachedTransports: [ + (logObj) => { + rfs.write(JSON.stringify(logObj) + "\n"); + }, + ], + }); + return log +} + +export const toolLoggerTS = (name, options: IKBotTask) => { + let log = createLogger(name) + //log.settings.minLevel = options.logLevel + log = createFileLogger(log,options.logLevel, path.join(options.logs,`tools-${name}.json`)) + return log +} + +export const toolLogger = (name, options: IKBotTask = { logs: process.cwd() } as IKBotTask ) => { + const logPath = path.resolve(path.join(options.logs || './',`tools-${name}.json`)) + const log = winstonLogger(name, logPath, ELogTargets.Console) + return log +} + +export * from './types.js' +export * from './types_kbot.js' diff --git a/packages/kbot/src/ai-tools/invoke.ts b/packages/kbot/src/ai-tools/invoke.ts new file mode 100644 index 00000000..30573096 --- /dev/null +++ b/packages/kbot/src/ai-tools/invoke.ts @@ -0,0 +1,55 @@ +import { tools } from '../lib/tools/tools.js' +import { logger } from '../index.js' +import { InvokeToolSchema } from '../zod_schemas.js' +import { toYargs } from '@polymech/commons/schemas' +import { sync as write } from '@polymech/fs/write' +import type { Argv } from 'yargs' +import * as path from 'path' + +const options = (yargs: Argv) => toYargs(yargs, InvokeToolSchema); + +export const invoke = async (argv: any) => { + try { + const { tools: toolCategory, function: funcName, target, params, output } = argv; + + // Get tool category + const toolSet = tools[toolCategory]; + if (!toolSet) { + logger.error(`Tool category '${toolCategory}' not found`); + return; + } + + // Initialize tools with target directory + const toolList = toolSet(target); + + // Find specific function + const tool = toolList.find(t => t.function.name === funcName); + if (!tool) { + logger.error(`Function '${funcName}' not found in ${toolCategory} tools`); + return; + } + + // Parse parameters if provided + const parameters = params ? JSON.parse(params) : {}; + + // Execute tool function + logger.info(`Invoking ${toolCategory}::${funcName}`); + const result = await tool.function.function(parameters); + + // Handle output + if (output) { + const outputPath = path.isAbsolute(output) ? output : path.join(process.cwd(), output); + logger.info(`Writing output to ${outputPath}`); + write(outputPath, JSON.stringify(result, null, 2)); + } else { + logger.info('Result:', result); + } + + return result; + } catch (error) { + logger.error('Error invoking tool:', error); + throw error; + } +}; + +export { options as invokeOptions }; \ No newline at end of file diff --git a/packages/kbot/src/ai-tools/lib/tools/fs.ts b/packages/kbot/src/ai-tools/lib/tools/fs.ts new file mode 100644 index 00000000..082689ea --- /dev/null +++ b/packages/kbot/src/ai-tools/lib/tools/fs.ts @@ -0,0 +1,435 @@ +import * as path from 'path' +import { RunnableToolFunction } from 'openai/lib/RunnableFunction' +import { sync as rm } from '@polymech/fs/remove' +import { isString } from '@polymech/core/primitives' +import { sync as write } from '@polymech/fs/write' +import { sync as read } from '@polymech/fs/read' +import { sync as rename } from '@polymech/fs/rename' +import { sync as exists } from '@polymech/fs/exists' +import { sanitize } from "@polymech/fs/utils" +import { filesEx } from '@polymech/commons' + +import { toolLogger } from '../../index.js' +import { IKBotTask } from '../../types.js' +import { EXCLUDE_GLOB } from '../../constants.js' + +import { glob } from 'glob' + +const isBase64 = (str: string): boolean => { + // 1. Quick checks for length & allowed characters: + // - Must be multiple of 4 in length + // - Must match Base64 charset (A-Z, a-z, 0-9, +, /) plus optional "=" padding + if (!str || str.length % 4 !== 0) { + return false; + } + + const base64Regex = /^[A-Za-z0-9+/]+={0,2}$/; + if (!base64Regex.test(str)) { + return false; + } + + // 2. Attempt decode–re-encode to confirm validity: + try { + const decoded = atob(str); // Decode from Base64 + const reencoded = btoa(decoded); // Re-encode to Base64 + + // Compare the re-encoded string to original + return reencoded === str; + } catch { + return false; + } + } + +export const decode_base64 = (base64: string): string => { + try { + if(!isBase64(base64)) { + return base64 + } + return Buffer.from(base64, 'base64').toString('utf-8'); + } catch (error) { + throw new Error('Failed to decode base64 string'); + } +}; + +// Helper function for smart Base64 decoding +const decodeContentSmart = (content: string, logger: any, identifier: string): string => { + if (!content || typeof content !== 'string') { + return content; // Return original content if null, undefined, or not a string + } + + const lines = content.split(/\r?\n/); + const processedLines = lines.map(line => { + const trimmedLine = line.trim(); + if (!trimmedLine) { + return ''; // Preserve empty lines between potential blocks but decode the blocks themselves + } + + try { + // Attempt to decode Base64 + const decodedLine = Buffer.from(trimmedLine, 'base64').toString('utf-8'); + // Validate if it was actually Base64 by re-encoding + const reEncodedLine = Buffer.from(decodedLine, 'utf-8').toString('base64'); + + // Revised Validation Check: + // Compare original trimmed line with re-encoded line. + // Allow for potential padding differences by checking both exact match and no-pad match. + const originalNoPad = trimmedLine.replace(/={1,2}$/, ''); + const reEncodedNoPad = reEncodedLine.replace(/={1,2}$/, ''); + + if (reEncodedLine === trimmedLine || reEncodedNoPad === originalNoPad) { + logger.debug(`Successfully decoded Base64 line for ${identifier}`); + return decodedLine; + } + // If validation fails, treat as plain text + logger.debug(`Re-encoding mismatch for ${identifier}. Original: '${trimmedLine}', Re-encoded: '${reEncodedLine}', using original trimmed line.`); + return trimmedLine; + } catch (decodeError) { + // If decoding throws an error, assume it's plain text + // Use debug level as this is expected for non-base64 lines + logger.debug(`Base64 decoding failed for line in ${identifier}, assuming plain text. Line: ${trimmedLine}`); + return trimmedLine; // Return original trimmed line + } + }); + + + // Join the processed lines back together + return processedLines.join('\n'); +}; + +export const tools = (target: string, options: IKBotTask): Array => { + const logger = toolLogger('fs', options) + + return [ + { + type: 'function', + function: { + name: 'list_files', + description: 'List all files in a directory', + parameters: { + type: 'object', + properties: { + directory: { type: 'string' }, + pattern: { type: 'string', optional: true } + }, + required: ['directory'] + }, + function: async (params: any) => { + try { + const directory = path.join(target, sanitize(params.directory)); + if (!exists(directory)) { + logger.debug(`Tool::ListFiles Directory ${directory} does not exist`); + return [] + } + let pattern = params.pattern || '**/*'; + logger.debug(`Tool::ListFiles Listing files in ${directory} with pattern ${pattern}`); + pattern = [ + ...EXCLUDE_GLOB, + pattern + ] + const ret = await glob(pattern, { + cwd: directory, + absolute: false, + ignore: EXCLUDE_GLOB + }); + return ret + } catch (error) { + logger.error('Error listing files', error); + throw error; + } + }, + parse: JSON.parse + } + } as RunnableToolFunction, + { + type: 'function', + function: { + name: 'read_files', + description: 'Reads files in a directory with a given pattern', + parameters: { + type: 'object', + properties: { + directory: { type: 'string' }, + pattern: { type: 'string', optional: true } + }, + required: ['directory'] + }, + function: async (params: any) => { + try { + const pattern = params.pattern || '**/*'; + let entries = filesEx(target, pattern); + let ret = entries.map((entry) => { + try { + let content = read(entry); + return { + path: path.relative(target, entry).replace(/\\/g, '/'), + content: content.toString() + } + } catch (error) { + logger.error(`Error reading file ${entry}:`, error) + return null + } + }) + ret = ret.filter((entry) => (entry !== null && entry.content)) + logger.debug(`Tool::ReadFiles Reading files in ${target} with pattern ${pattern} : ${ret.length} files`, ret.map((entry) => entry.path)); + return ret + } catch (error) { + logger.error('Error listing files', error); + throw error; + } + }, + parse: JSON.parse + } + } as RunnableToolFunction, + { + type: 'function', + function: { + name: 'remove_file', + description: 'Remove a file at given path', + parameters: { + type: 'object', + properties: { + path: { type: 'string' } + }, + required: ['path'] + }, + function: async (params: any) => { + try { + const filePath = path.join(target, sanitize(params.path)); + logger.debug(`Tool::RemoveFile Removing file ${filePath}`); + rm(filePath); + return true; + } catch (error) { + logger.error('Error removing file', error); + throw error; + } + }, + parse: JSON.parse + } + } as RunnableToolFunction, + { + type: 'function', + function: { + name: 'rename_file', + description: 'Rename or move a file or directory', + parameters: { + type: 'object', + properties: { + src: { type: 'string' }, + dst: { type: 'string' } + }, + required: ['path'] + }, + function: async (params: any) => { + try { + const src = path.join(target, sanitize(params.src)) + const dst = path.join(target, sanitize(params.dst)) + logger.debug(`Tool::Rename file ${src} to ${dst}`) + rename(src, dst) + rm(src) + return true + } catch (error) { + logger.error('Error removing file', error) + throw error + } + }, + parse: JSON.parse + } + } as RunnableToolFunction, + { + type: 'function', + function: { + name: "modify_project_files", + description: "Create or modify existing project files in one shot, preferably used for creating project structure)", + parameters: { + type: "object", + properties: { + files: { + type: "array", + items: { + type: "object", + properties: { + path: { type: "string" }, + content: { type: "string", description: "new file content (Part of JSON payload)" } + }, + required: ["path", "content"] + } + } + }, + required: ["files"], + }, + function: async (ret) => { + try { + if (!target) { + logger.error(`Tool::FS:modify_project_files : Root path required`) + return + } + let { files } = ret as any + if (isString(files)) { + try { + files = JSON.parse(files) + } catch (error: any) { + logger.error(`Tool::modify_project_files : Structure Error parsing files`, error, ret) + // Consider writing the raw input for debugging if JSON parsing fails + // write(path.join(target, 'tools-output-error.json'), files) + return error.message + } + } + for (const file of files) { + const sanitizedPath = sanitize(file.path); + const filePath = path.join(target, sanitizedPath); + logger.debug(`Tool:modify_project_files writing file ${filePath}`) + try { + // const contentToWrite = decodeContentSmart(file.content, logger, sanitizedPath); + try { + await write(filePath, file.content) + } catch (writeError) { + logger.error(`Tool:modify_project_files Error writing file ${filePath}`, writeError) + } + } catch (error) { + logger.error(`Tool:modify_project_files Error processing file content for ${filePath}`, error) + } + } + } catch (error) { + logger.error(`Error creating project structure`, error) + } + }, + + parse: JSON.parse, + }, + } as RunnableToolFunction<{ id: string }>, + { + type: 'function', + function: { + name: "write_file", + description: "Writes to a file, given a path and content (Part of JSON payload). No directory or file exists check needed!", + parameters: { + type: "object", + properties: { + file: { + type: "object", + properties: { + path: { type: "string" }, + content: { type: "string", description: "new file content (Part of JSON payload)" } + } + } + }, + required: ["file"], + }, + function: async (params) => { + let fileInfo; + try { + if (isString(params)) { + try { + params = JSON.parse(params) + } catch (error: any) { + logger.error(`Tool::write_file : Structure Error parsing JSON`, error, params) + return error.message + } + } + + fileInfo = (params as any).file; // Keep fileInfo accessible + + if (!target || !fileInfo || !fileInfo.path || typeof fileInfo.content === 'undefined') { + logger.error(`Tool::write_file : Path/Target/Content are required`, fileInfo) + return false; // Indicate failure + } + + const sanitizedPath = sanitize(fileInfo.path); + const filePath = path.join(target, sanitizedPath) + logger.debug(`Tool::write_file Writing file ${filePath}`) + try { + // Use the smart decoding helper function + // const contentToWrite = decodeContentSmart(fileInfo.content, logger, sanitizedPath); + await write(filePath, fileInfo.content) + return true + } catch (error) { + // Log error related to processing or writing the file + logger.error(`Tool:write_file Error processing or writing file ${sanitizedPath}`, error) + return false // Indicate failure + } + } catch (error) { + logger.error(`Tool:write_file Error writing file ${fileInfo?.path ? sanitize(fileInfo.path) : 'unknown'}`, error) + return false // Indicate failure + } + }, + parse: JSON.parse, + }, + } as RunnableToolFunction<{ id: string }>, + { + type: 'function', + function: { + name: "file_exists", + description: "check if a file or folder exists", + parameters: { + type: "object", + properties: { + file: { + type: "object", + properties: { + path: { type: "string" } + } + } + }, + required: ["file"], + }, + function: async (ret) => { + try { + if (isString(ret)) { + try { + ret = JSON.parse(ret) + } catch (error: any) { + logger.error(`Tool::file_exists : Structure Error parsing files`, error, ret) + return error.message + } + } + const { file } = ret as any + if (!target || !file.path) { + logger.error(`Tool::file_exists : Path is required`, ret) + return + } + const sanitizedPath = sanitize(file.path); + const filePath = path.join(target, sanitizedPath) + const res = exists(filePath) + logger.debug(`Tool::file_exists ${filePath} exists: ${res}`) + return res ? true : false + } catch (error) { + logger.error(`Tool:file_exists error`, error) + return false + } + }, + parse: JSON.parse, + }, + } as RunnableToolFunction<{ id: string }>, + { + type: 'function', + function: { + name: "read_file", + description: "read a file, at given a path", + parameters: { + type: "object", + properties: { + file: { + type: "object", + properties: { + path: { type: "string" } + } + } + }, + required: ["file"], + }, + function: async (ret) => { + try { + const { file } = ret as any + const sanitizedPath = sanitize(file.path); + const filePath = path.join(target, sanitizedPath) + logger.debug(`Tool::ReadFile Reading file ${filePath}`) + return read(filePath, 'string') + } catch (error) { + logger.error(`Error reading file`, error) + } + }, + parse: JSON.parse + } + } as RunnableToolFunction<{ id: string }> + ] +}; diff --git a/packages/kbot/src/ai-tools/lib/tools/git.ts b/packages/kbot/src/ai-tools/lib/tools/git.ts new file mode 100644 index 00000000..c8fb6ab8 --- /dev/null +++ b/packages/kbot/src/ai-tools/lib/tools/git.ts @@ -0,0 +1,157 @@ +import * as path from 'path' +import { RunnableToolFunction } from 'openai/lib/RunnableFunction' + +import { simpleGit } from 'simple-git' + +import { sync as exists } from '@polymech/fs/exists' +import { substitute } from '@polymech/commons' + +import { logger } from '../../index.js' +import { toolLogger } from '../../index.js' +import { IKBotTask } from '../../types.js' + +import { findUpSync } from 'find-up' + +const commitFiles = async (filePaths: string[], commitMessage: string, targetDirectory: string, variables: Record = {}) => { + try { + if (!filePaths || !filePaths.length) { + logger.warn(`No files to commit`) + return + } + if (!exists(path.join(targetDirectory, '.git'))) { + try { + logger.info(`Initializing repository at ${targetDirectory}`) + await initRepository(targetDirectory) + } catch (e: any) { + logger.error(`Error initializing repository at ${targetDirectory} `, e.message, filePaths) + } + } + + const git: any = simpleGit(targetDirectory); + try { + await git.add(filePaths); + } catch (e: any) { + logger.error('Error adding files:', e.message, filePaths); + } + await git.commit(commitMessage) + try { + await git.raw(['branch', '-M', 'master']); + const repo = substitute(false, "${GIT_REPO}/${GIT_USER}/${REPO_NAME}.git", { + REPO_NAME: path.basename(targetDirectory), + ...variables + }) + await git.raw(['remote', 'add', 'origin', repo]) + await git.push(['--set-upstream', 'origin', 'master']) + return true + } catch (e: any) { + if (e.message.includes('remote origin already exists')) { + await git.push(['--set-upstream', 'origin', 'master']); + } else { + logger.error('Tools::GIT : Error pushing files:', e.message, filePaths); + } + } + } catch (error: any) { + logger.error('Error committing files:', error.message, filePaths); + throw error + } +} + +const initRepository = async (targetDirectory: string, variables: Record = {}): Promise => { + try { + const git: any = simpleGit(targetDirectory); + if (!exists(path.join(targetDirectory, '.git'))) { + await git.init(); + logger.info('Git repository initialized successfully!'); + return true; + } + logger.info('Git repository already exists'); + return false + } catch (error: any) { + logger.error('Error initializing git repository:', error.message); + return false + } +} + +export const tools = (target: string, options: IKBotTask): Array => { + const logger = toolLogger('git', options) + if (!target) { + logger.warn(`Tools:GIT : Target is required`) + return [] + } + if (!exists(target)) { + logger.warn(`Tools:GIT : Project path doesnt exists ${target}`) + return [] + } + return [ + { + type: 'function', + function: { + name: "init_repository", + description: "Initialize a new git repository", + parameters: { + type: "object", + properties: {}, + required: [] + }, + function: async (params) => { + logger.info(`Tool::init_repository Init Repository in ${target}`) + const gitDir = findUpSync('.git',{ type: 'directory', cwd: target}) + if(gitDir && exists(gitDir)){ + logger.info(`Repository already exists at ${gitDir}`) + return true + } + try { + const ret = await initRepository(target, options.variables) + return true + } catch (error) { + logger.error(`Error initializing repository`, error) + return false; + } + }, + parse: JSON.parse, + } + } as RunnableToolFunction<{ id: string }>, + { + type: 'function', + function: { + name: "commit_files_git", + description: "Commit files using git", + parameters: { + type: "object", + properties: { + files: { + type: "array", + items: { + type: "string" + } + }, + message: { + type: "string" + } + }, + required: ["files"], + }, + function: async (ret) => { + debugger + try { + const { files, message } = ret as any + logger.info(`Tool::GIT Commit files ${files} in ${target}`) + if (!target) { + logger.error(`Tool::Git Commit : Target is required`) + return + } + if (!exists(target)) { + logger.error(`Project doesnt path exists ${target}`) + return + } + await commitFiles(files, message, target, options.variables) + } catch (error: any) { + logger.error(`Error committing dependencies : ${error.message}`) + } + return true + }, + parse: JSON.parse, + }, + } as RunnableToolFunction<{ id: string }> + ] +} \ No newline at end of file diff --git a/packages/kbot/src/ai-tools/lib/tools/index.ts b/packages/kbot/src/ai-tools/lib/tools/index.ts new file mode 100644 index 00000000..bc5b02f8 --- /dev/null +++ b/packages/kbot/src/ai-tools/lib/tools/index.ts @@ -0,0 +1,30 @@ +import { RunnableToolFunctionWithParse } from 'openai/lib/RunnableFunction' +import { JSONSchema } from 'openai/lib/jsonschema' +import { ZodSchema, z } from 'zod' + +// see https://github.com/openai/openai-node/blob/master/examples/tool-call-helpers-zod.ts +export const zodFunction =({ + function: fn, + schema, + description = '', + name, + }: { + function: (args: T) => Promise + schema: ZodSchema + description?: string + name?: string + }): RunnableToolFunctionWithParse => { + return { + type: 'function', + function: { + function: fn, + name: name ?? fn.name, + description: description, + parameters: z.toJSONSchema(schema) as JSONSchema, + parse(input: string): T { + const obj = JSON.parse(input) + return schema.parse(obj) + } + } + } + } \ No newline at end of file diff --git a/packages/kbot/src/ai-tools/lib/tools/interact.ts b/packages/kbot/src/ai-tools/lib/tools/interact.ts new file mode 100644 index 00000000..b8ded940 --- /dev/null +++ b/packages/kbot/src/ai-tools/lib/tools/interact.ts @@ -0,0 +1,89 @@ +import * as path from 'path' +import { RunnableToolFunction } from 'openai/lib/RunnableFunction' +import { toolLogger } from '../../index.js' +import { IKBotTask } from '../../types.js' +import { input, select } from '@inquirer/prompts' +export const tools = (target: string, options: IKBotTask): Array => { + const logger = toolLogger('interact', options) + return [ + { + type: 'function', + function: { + name: 'ask_question', + description: 'Ask user a simple question and get response', + parameters: { + type: 'object', + properties: { + question: { + type: 'string', + description: 'Question to ask the user' + }, + default: { + type: 'string', + description: 'Default answer', + optional: true + } + }, + required: ['question'] + }, + function: async (params: any) => { + try { + const answer = await input( + { + message: params.question, + default: params.default + } + ) + return { response: answer } + } catch (error: any) { + logger.error('Error asking question:', error.message); + return null; + } + }, + parse: JSON.parse + } + } as RunnableToolFunction, + { + type: 'function', + function: { + name: 'choose_option', + description: 'Ask user to choose from multiple options', + parameters: { + type: 'object', + properties: { + message: { + type: 'string', + description: 'Message to show the user' + }, + choices: { + type: 'array', + items: { type: 'string' }, + description: 'List of choices' + }, + multiple: { + type: 'boolean', + description: 'Allow multiple selections', + optional: true + } + }, + required: ['message', 'choices'] + }, + function: async (params: any) => { + try { + const answer = await select( + { + message: params.message, + choices: params.choices + } + ); + return { response: answer } + } catch (error: any) { + logger.error('Error in choice selection:', error.message); + return null; + } + }, + parse: JSON.parse + } + } as RunnableToolFunction + ] +} \ No newline at end of file diff --git a/packages/kbot/src/ai-tools/lib/tools/keyv.ts b/packages/kbot/src/ai-tools/lib/tools/keyv.ts new file mode 100644 index 00000000..76bd1d02 --- /dev/null +++ b/packages/kbot/src/ai-tools/lib/tools/keyv.ts @@ -0,0 +1,21 @@ +import * as path from 'path' +import Keyv from 'keyv' +import { KeyvFile } from 'keyv-file' + +import { resolve } from '@polymech/commons' + +export const store = (storePath: string, ns: string = 'ns-unknown', opts: any = {}) => { + const keyvFile = new KeyvFile({ + filename: path.resolve(resolve(storePath)), + writeDelay: 100, // ms + }) + return new Keyv({ store: keyvFile, namespace: ns, ...opts }) +} +export const get = async (key: string, storePath: string, ns: string = 'ns-unknown', opts: any = {}) => { + const keyv = store(storePath, ns, opts) + return await keyv.get(key) +} +export const set = async (key: string, value: any, storePath: string, ns: string = 'ns-unknown', opts: any = {}) => { + const keyv = store(storePath, ns, opts) + return await keyv.set(key, value) +} diff --git a/packages/kbot/src/ai-tools/lib/tools/memory.ts b/packages/kbot/src/ai-tools/lib/tools/memory.ts new file mode 100644 index 00000000..d943e36b --- /dev/null +++ b/packages/kbot/src/ai-tools/lib/tools/memory.ts @@ -0,0 +1,379 @@ +import * as path from 'path' +import { RunnableToolFunction } from 'openai/lib/RunnableFunction' +import { isString } from '@polymech/core/primitives' + +import { toolLogger } from '../../index.js' +import { IKBotTask } from '../../types.js' + +import { store, get, set } from './keyv.js' + +// Helper function to get storage path +const getStoragePath = (options: IKBotTask): string => { + // For now, use default path. Later this can be configured via options + return path.join(process.cwd(), 'memory.json'); +}; + +// Default collection name when none provided +const DEFAULT_COLLECTION = 'no-collection'; + +// Supported data formats +type DataFormat = 'text' | 'json' | 'binary'; + +// Memory entry structure +interface MemoryEntry { + value: string; + meta: { + type: DataFormat; + created: string; + updated: string; + }; +} + +// Helper function to process value based on format +const processValueForStorage = (value: string, format: DataFormat): string => { + switch (format) { + case 'json': + try { + // Validate JSON by parsing and re-stringifying + JSON.parse(value); + return value; + } catch (error) { + throw new Error('Invalid JSON format provided'); + } + case 'binary': + // For binary, we expect base64 encoded data + try { + // Validate base64 + Buffer.from(value, 'base64'); + return value; + } catch (error) { + throw new Error('Invalid base64 format for binary data'); + } + case 'text': + default: + return value; + } +}; + +// Helper function to create memory entry +const createMemoryEntry = (value: string, format: DataFormat): MemoryEntry => { + const now = new Date().toISOString(); + return { + value: processValueForStorage(value, format), + meta: { + type: format, + created: now, + updated: now + } + }; +}; + +export const tools = (target: string, options: IKBotTask): Array => { + const logger = toolLogger('memory', options) + const storagePath = getStoragePath(options); + + return [ + { + type: 'function', + function: { + name: 'memorize', + description: `Store information in memory as a key-value collection with format support. Supports text, JSON, and binary (base64) formats. + +Returns: { + success: boolean, + message: string, + meta: { + type: "text" | "json" | "binary", + created: string (ISO timestamp), + updated: string (ISO timestamp) + } +}`, + parameters: { + type: 'object', + properties: { + collection: { + type: 'string', + description: 'Collection name to organize related data (defaults to "no-collection" if not provided). Acts like a namespace.', + optional: true + }, + key: { + type: 'string', + description: 'Unique identifier for the data within the collection. Must be a string.' + }, + value: { + type: 'string', + description: 'The data to store. For format="text": any string. For format="json": valid JSON string. For format="binary": base64 encoded data.' + }, + format: { + type: 'string', + description: 'Data format type. "text" for plain text (default), "json" for JSON data (validates structure), "binary" for base64 encoded binary data.', + enum: ['text', 'json', 'binary'], + optional: true + } + }, + required: ['key', 'value'] + }, + function: async (params: any) => { + try { + const { collection = DEFAULT_COLLECTION, key, value, format = 'text' } = params; + logger.debug(`Tool::Memorize Storing ${key} in collection ${collection} as ${format}`); + + const memoryEntry = createMemoryEntry(value, format as DataFormat); + await set(`${collection}:${key}`, memoryEntry, storagePath, collection); + + return { + success: true, + message: `Stored ${key} in collection ${collection} as ${format}`, + meta: memoryEntry.meta + }; + } catch (error) { + logger.error('Error storing memory', error); + return { + success: false, + message: error instanceof Error ? error.message : 'Unknown error occurred' + }; + } + }, + parse: JSON.parse + } + } as RunnableToolFunction, + { + type: 'function', + function: { + name: 'recall', + description: `Retrieve stored information from memory by collection and key, including format metadata. + +Returns: { + success: boolean, + value?: string (the stored data), + meta?: { + type: "text" | "json" | "binary", + created: string (ISO timestamp), + updated: string (ISO timestamp) + }, + key: string, + collection: string, + message?: string (error message if success=false) +}`, + parameters: { + type: 'object', + properties: { + collection: { + type: 'string', + description: 'Collection name to retrieve from (defaults to "no-collection" if not provided). Must match the collection used when storing.', + optional: true + }, + key: { + type: 'string', + description: 'The unique identifier of the data to retrieve. Must match the key used when storing.' + } + }, + required: ['key'] + }, + function: async (params: any) => { + try { + const { collection = DEFAULT_COLLECTION, key } = params; + logger.debug(`Tool::Recall Retrieving ${key} from collection ${collection}`); + + const storedData = await get(`${collection}:${key}`, storagePath, collection); + if (storedData === undefined) { + return { success: false, message: `Key ${key} not found in collection ${collection}` }; + } + + // Handle both old format (plain string) and new format (MemoryEntry) + let memoryEntry: MemoryEntry; + if (typeof storedData === 'string') { + // Legacy format - convert to new format + memoryEntry = { + value: storedData, + meta: { + type: 'text', + created: new Date().toISOString(), + updated: new Date().toISOString() + } + }; + } else { + memoryEntry = storedData as MemoryEntry; + } + + return { + success: true, + value: memoryEntry.value, + meta: memoryEntry.meta, + key, + collection + }; + } catch (error) { + logger.error('Error retrieving memory', error); + return { + success: false, + message: error instanceof Error ? error.message : 'Unknown error occurred' + }; + } + }, + parse: JSON.parse + } + } as RunnableToolFunction, + { + type: 'function', + function: { + name: 'forget', + description: `Remove a specific key from memory collection. + +Returns: { + success: boolean, + message: string (confirmation or error message) +}`, + parameters: { + type: 'object', + properties: { + collection: { + type: 'string', + description: 'Collection name to remove from (defaults to "no-collection" if not provided). Must match the collection where the key was stored.', + optional: true + }, + key: { + type: 'string', + description: 'The unique identifier of the data to remove. Must match exactly the key used when storing.' + } + }, + required: ['key'] + }, + function: async (params: any) => { + try { + const { collection = DEFAULT_COLLECTION, key } = params; + logger.debug(`Tool::Forget Removing ${key} from collection ${collection}`); + + const keyv = store(storagePath, collection); + const deleted = await keyv.delete(`${collection}:${key}`); + return { success: deleted, message: deleted ? `Removed ${key} from ${collection}` : `Key ${key} not found in ${collection}` }; + } catch (error) { + logger.error('Error removing from memory', error); + return { + success: false, + message: error instanceof Error ? error.message : 'Unknown error occurred' + }; + } + }, + parse: JSON.parse + } + } as RunnableToolFunction, + { + type: 'function', + function: { + name: 'list_memories', + description: `List all keys in a specific collection using Keyv's iterator method. + +Returns: { + success: boolean, + collection: string (the collection name), + keys: string[] (array of key names in the collection), + entries: Array<{ + key: string, + meta?: { + type: "text" | "json" | "binary", + created: string (ISO timestamp), + updated: string (ISO timestamp) + } + }>, + count: number (total number of keys), + message?: string (info or error message) +}`, + parameters: { + type: 'object', + properties: { + collection: { + type: 'string', + description: 'Collection name to list keys from (defaults to "no-collection" if not provided). Will return all keys stored in this collection namespace.', + optional: true + } + }, + required: [] + }, + function: async (params: any) => { + try { + const { collection = DEFAULT_COLLECTION } = params; + + logger.debug(`Tool::ListMemories Listing keys in collection ${collection}`); + + // Create a Keyv instance for the specific collection to use iterator + const keyv = store(storagePath, collection); + const keys: string[] = []; + const entries: { key: string; meta?: any }[] = []; + + try { + // Check if iterator method exists and use it + if (typeof keyv.iterator === 'function') { + try { + // Try calling iterator without arguments first + const iterator = (keyv as any).iterator(); + for await (const [key, value] of iterator) { + // Remove the collection prefix from the key to get the clean key name + const cleanKey = key.replace(`${collection}:`, ''); + keys.push(cleanKey); + + // Try to extract metadata if it's a MemoryEntry + let meta = undefined; + if (value && typeof value === 'object' && value.meta) { + meta = value.meta; + } + + entries.push({ key: cleanKey, meta }); + } + } catch (iteratorCallError) { + logger.warn(`Tool::ListMemories Iterator call failed:`, iteratorCallError); + // Fall through to the not available case + return { + success: true, + collection, + keys: [], + entries: [], + count: 0, + message: 'Iterator call failed. Unable to list keys.' + }; + } + } else { + // Iterator not available, provide helpful message + logger.warn(`Tool::ListMemories Iterator method not available for Keyv instance`); + return { + success: true, + collection, + keys: [], + entries: [], + count: 0, + message: 'Iterator method not available in this Keyv version. Use individual key operations instead.' + }; + } + + return { + success: true, + collection, + keys, + entries, + count: keys.length + }; + } catch (iteratorError) { + // If iterator fails, fall back to returning basic info + logger.warn(`Tool::ListMemories Iterator failed for collection ${collection}:`, iteratorError); + return { + success: true, + collection, + keys: [], + entries: [], + count: 0, + message: 'Iterator failed or collection is empty' + }; + } + } catch (error) { + logger.error('Error listing memories', error); + return { + success: false, + message: error instanceof Error ? error.message : 'Unknown error occurred' + }; + } + }, + parse: JSON.parse + } + } as RunnableToolFunction + ] +}; diff --git a/packages/kbot/src/ai-tools/lib/tools/npm.ts b/packages/kbot/src/ai-tools/lib/tools/npm.ts new file mode 100644 index 00000000..4c066c4a --- /dev/null +++ b/packages/kbot/src/ai-tools/lib/tools/npm.ts @@ -0,0 +1,151 @@ +import path from 'path' +import { RunnableToolFunction } from 'openai/lib/RunnableFunction' +import { exec } from 'child_process' +import { promisify } from 'util' +import { logger } from '../../index.js' +import pMap from "p-map" +import { sync as exists } from '@polymech/fs/exists' +import { IKBotTask } from '../../types.js' +import { toolLogger } from '../../index.js' + +const execAsync = promisify(exec) +const install = async (dependency: string, directory: string): Promise => { + return new Promise((resolve, reject) => { + const command = `pnpm add ${dependency} --dir ${directory}` + exec(command, (error, stdout, stderr) => { + if (error) { + logger.error(`Error installing ${dependency}:`, error.message) + return resolve(false) + } + logger.info(`Successfully installed "${dependency}" in "${directory}".`) + }) + }) +} +export const tools = (target: string, options: IKBotTask): Array => { + const logger = toolLogger('npm', options) + return [ + { + type: 'function', + function: { + name: 'build_project', + description: 'Build project using pnpm build command', + parameters: { + type: 'object', + properties: {}, + required: [] + }, + function: async () => { + try { + logger.debug(`Tool::BuildProject Building project at ${target}`); + const { stdout, stderr } = await execAsync('pnpm build', { + cwd: target + }); + return { + success: !stderr, + output: stdout, + error: stderr || null + }; + } catch (error: any) { + logger.error('Error building project', error); + return { + success: false, + output: null, + error: error.message + }; + } + }, + parse: JSON.parse + } + } as RunnableToolFunction, + { + type: 'function', + function: { + name: 'run_npm', + description: 'Run an npm/pnpm command', + parameters: { + type: 'object', + properties: { + command: { type: 'string', description: 'Command to run (e.g. install, test, etc)' }, + args: { + type: 'array', + items: { type: 'string' }, + description: 'Additional arguments for the command', + optional: true + } + }, + required: ['command'] + }, + function: async (params: any) => { + try { + const args = params.args ? params.args.join(' ') : ''; + const fullCommand = `pnpm ${params.command} ${args}`.trim(); + logger.debug(`Tool::RunNpm Running command: ${fullCommand}`); + const { stdout, stderr } = await execAsync(fullCommand, { + cwd: target + }); + + return { + success: !stderr, + output: stdout, + error: stderr || null + }; + } catch (error: any) { + logger.error('Error running npm command', error); + return { + success: false, + output: null, + error: error.message + }; + } + }, + parse: JSON.parse + } + } as RunnableToolFunction, + { + type: 'function', + function: { + name: "install_dependency", + description: "Install a dependency using npm", + parameters: { + type: "object", + properties: { + dependencies: { + type: "array", + items: { + type: "string" + } + } + }, + required: ["dependencies"], + }, + function: async (ret) => { + try { + const { dependencies } = ret as any + if (!target) { + logger.error(`Tool::NPM Target is required to install dependencies`) + return + } + if (!exists(target)) { + logger.error(`Project doesnt path exists ${target}`) + return + } + await pMap(dependencies, (async (dependency: string) => { + logger.info(`Installing dependency`, dependency) + try { + return install(dependency, target) + } catch (error) { + logger.error(`Error installing dependency ${dependency} `, error) + } + }), { + concurrency: 1 + }) + + } catch (error) { + logger.error(`Error installing dependencies`, error) + } + }, + parse: JSON.parse, + } + } as RunnableToolFunction<{ id: string }> + ] +} \ No newline at end of file diff --git a/packages/kbot/src/ai-tools/lib/tools/process.ts b/packages/kbot/src/ai-tools/lib/tools/process.ts new file mode 100644 index 00000000..15984d95 --- /dev/null +++ b/packages/kbot/src/ai-tools/lib/tools/process.ts @@ -0,0 +1,130 @@ +import { logger } from '../../index.js' +import * as stream from 'stream' +import { ChildProcess, spawn } from 'child_process' + +export enum STATUS { + OK, + ERROR, + PENDING +} + +const fatalHandler = (message: string, fn: (msg: string) => void): boolean => { + if (message.startsWith('fatal:')) { + fn('\t\ ' + message) + return true; + } + return false +} + +const defaultFilter = (message: string): boolean => { + return message.length > 0 && + message !== '\n' && + message !== '\r' && + message !== '\r\n' && + !message.startsWith('Debugger attached') && + !message.includes('NODE_TLS_REJECT_UNAUTHORIZED') && + !message.includes('Waiting for the debugger to disconnect') +} + +const subscribe = (signal: stream.Readable, collector: (data: any) => void = () => { }) => { + if(!signal || !signal.on) { + return + } + signal.on('message', (message) => logger.debug('message', message)) + signal.on('error', (error) => logger.error('std-error', error)) + signal.on('data', (data) => { + /* + const msg = data.toString().replace(ansiRegex(), "") + if (!defaultFilter(msg)) { + return + } + collector(msg)*/ + process.stdout.write(data) + + }) +} +const merge = (buffer: string[], data: any): string[] => buffer.concat(data); + +const hook = (child: ChildProcess, resolve: any, reject: any, cmd: string, buffer: string[] = []) => { + const collector = (data: any) => { buffer.push(data) } + //subscribe(child.stderr, collector) + //process.stdin.pipe(child.stdin) + debugger + child.on('exit', (code, signal) => { + debugger + if (code) { + resolve({ + code: STATUS.ERROR, + command: cmd, + error: code, + messages: buffer + }) + } else { + resolve({ + code: STATUS.OK, + command: cmd, + messages: buffer + }) + } + }) + return child +} + +export class Process { + public binary = '' + public cwd: string = '' + public args: string = '' + public buffer: string[] = [] + constructor(options: any = {}) { + this.binary = options.binary || this.binary + this.cwd = options.cwd || process.cwd() + this.buffer = options.buffer || [] + } + public async exec(command: string, args: string[] = []): Promise { + args = [command].concat(args) + try { + let cmd = `${this.binary} ${args.join(' ')}` + /* + const p = new Promise((resolve, reject) => { + const p = exec(cmd, { + cwd: this.cwd + }) + return hook(p, resolve, reject, this.binary + ' ' + args.join(' '), this.buffer) + }) + return p + */ + try { + //stdio: ['pipe', 'pipe', 'pipe'], + debugger + const p = new Promise((resolve, reject) => { + const cp = spawn(cmd, args, { + cwd: this.cwd, + shell: true, + stdio:'inherit', + env: { + ...process.env + }, + }) + return hook(cp, resolve, reject, cmd, this.buffer) + }) + return p + } catch (e) { + logger.error('Error executing command', e) + } + } catch (e) { + logger.error('Error executing command', e) + } + } +} + +export class Helper { + public static async run(cwd, cmd: string, args: string[], buffer: string[] = [], debug_stream: boolean = false): Promise { + debug_stream && logger.info(`Run ${cmd} in ${cwd}`, args) + const gitProcess = new Process({ + cwd, + binary: cmd, + buffer + }) + return gitProcess.exec('', args) + } +} \ No newline at end of file diff --git a/packages/kbot/src/ai-tools/lib/tools/search.ts b/packages/kbot/src/ai-tools/lib/tools/search.ts new file mode 100644 index 00000000..83f79183 --- /dev/null +++ b/packages/kbot/src/ai-tools/lib/tools/search.ts @@ -0,0 +1,102 @@ +import * as path from 'path' +import { RunnableToolFunction } from 'openai/lib/RunnableFunction' +import { isArray } from '@polymech/core/primitives' +import { CONFIG_DEFAULT } from '@polymech/commons' +import { toolLogger } from '../../index.js' +import { IKBotTask } from '../../types.js' + +export const tools = (target: string, options: IKBotTask): Array => { + const logger = toolLogger('search', options) + return [ + { + type: 'function', + function: { + name: 'google', + description: 'Searches Google for the given query', + parameters: { + type: 'object', + properties: { + query: { type: 'string' } + }, + required: ['query'] + }, + function: async (params: any) => { + const { query } = params + const config = CONFIG_DEFAULT() as any + let apiKey = config?.google?.api_key + let cse = config?.google?.cse + if (!config || !apiKey || !cse) { + logger.debug( + "Config not found in $HOME/.osr/config.json. " + + "Optionally, export OSR_CONFIG with the path to the configuration file " + + "" + ); + return undefined + } + const res = await fetch( + `https://www.googleapis.com/customsearch/v1?key=${apiKey}&cx=${cse}&q=${encodeURIComponent( + query + )}` + ) + const data = await res.json(); + let results = + data.items?.map((item: { title?: string; link?: string; snippet?: string }) => ({ + title: item.title, + link: item.link, + snippet: item.snippet, + ...item + })) ?? []; + return JSON.stringify(results) + }, + parse: JSON.parse + } + } as RunnableToolFunction, + { + type: 'function', + function: { + name: 'serpapi', + description: 'Searches Serpapi (finds locations (engine:google_local), places on the map (engine:google_maps) ) for the given query', + parameters: { + type: 'object', + properties: { + query: { type: 'string' }, + engine: { type: 'string', default: 'google' }, + }, + required: ['query'] + }, + function: async (params: any) => { + const { query, engine } = params + const config = CONFIG_DEFAULT() as any + let apiKey = config?.serpapi?.key || config?.serpapi?.api_key + if (!config || !apiKey) { + logger.debug( + "Config not found in $HOME/.osr/config.json. " + + "Optionally, export OSR_CONFIG with the path to the configuration file " + + "" + ); + return undefined + } + const url = `https://serpapi.com/search?api_key=${apiKey}&engine=${engine || 'google'}&q=${encodeURIComponent(query)}&google_domain=google.com` + const res = await fetch(url) + logger.debug(`Searching ${url}`) + if (!res.ok) { + throw new Error(`HTTP error! status: ${res.status}`); + } + const data = await res.json() + let items = data.organic_results || data.local_results || data.place_results || data.places || data.maps_results || [] + if (items && !isArray(items)) { + items = [items] + } + let results = items.map((item: any) => ({ + title: item.title, + link: item.link, + snippet: item.snippet, + ...item + })) ?? [] + return JSON.stringify(results) + }, + parse: JSON.parse + } + } as RunnableToolFunction + ] +}; diff --git a/packages/kbot/src/ai-tools/lib/tools/terminal.ts b/packages/kbot/src/ai-tools/lib/tools/terminal.ts new file mode 100644 index 00000000..2536507b --- /dev/null +++ b/packages/kbot/src/ai-tools/lib/tools/terminal.ts @@ -0,0 +1,119 @@ +import * as path from 'path' +import { RunnableToolFunction } from 'openai/lib/RunnableFunction' +import { spawn } from 'child_process' +import { toolLogger } from '../../index.js' +import { IKBotTask } from '../../types.js' +import { Helper } from './process.js' + +export const tools = (target: string, options: IKBotTask): Array => { + const logger = toolLogger('terminal', options) + return [ + { + type: 'function', + function: { + name: 'execute_command', + description: 'Execute a terminal command and capture output', + parameters: { + type: 'object', + properties: { + command: { + type: 'string', + description: 'Command to execute' + }, + args: { + type: 'array', + items: { type: 'string' }, + description: 'Command arguments', + optional: true + }, + cwd: { + type: 'string', + description: 'Working directory for command execution', + optional: true + }, + background: { + type: 'boolean', + description: 'Run command in background (non-blocking)', + optional: true, + default: false + }, + window: { + type: 'boolean', + description: 'Open command in new terminal window', + optional: true, + default: false + }, + detached: { + type: 'boolean', + description: 'Run process detached from parent', + optional: true, + default: false + } + }, + required: ['command'] + }, + function: async (params: any) => { + try { + debugger + const cwd = params.cwd ? path.join(target, params.cwd) : target; + const args = params.args || []; + logger.debug(`Tool::Terminal : ExecuteCommand Running '${params.command}' in ${cwd}`, params) + if (params.detached) { + const isWindows = process.platform === 'win32'; + if (isWindows) { + spawn('cmd', ['/c', 'start', 'cmd', '/k', params.command, ...args], { + cwd: cwd, + detached: true, + stdio: 'ignore' + }); + } else { + // For macOS/Linux + spawn('x-terminal-emulator', ['-e', `${params.command} ${args.join(' ')}`], { + cwd: cwd, + detached: true, + stdio: 'ignore' + }); + } + return { + success: true, + output: 'Command launched in new window', + error: null + }; + } + + if (params.background || params.detached) { + const child = spawn(params.command, args, { + cwd: cwd, + detached: params.detached === true, + stdio: 'ignore' + }); + + if (params.detached) { + child.unref(); + } + + return { + success: true, + output: `Process started with PID: ${child.pid}`, + error: null + }; + } + const cmd = `${params.command} ${args.join(' ')}`.trim(); + logger.debug(`Tool::ExecuteCommand Running '${cmd}' in ${cwd}`); + const collector = [] + const ret = await Helper.run(cwd, cmd, [], collector, true) + return ret + } catch (error: any) { + logger.error('Error executing command', error); + return { + success: false, + output: null, + error: error.message + }; + } + }, + parse: JSON.parse + } + } as RunnableToolFunction + ] +} \ No newline at end of file diff --git a/packages/kbot/src/ai-tools/lib/tools/tools.ts b/packages/kbot/src/ai-tools/lib/tools/tools.ts new file mode 100644 index 00000000..bf4ff3ea --- /dev/null +++ b/packages/kbot/src/ai-tools/lib/tools/tools.ts @@ -0,0 +1,23 @@ +import { tools as fsTools } from './fs.js' +import { tools as npmTools } from './npm.js' +import { tools as gitTools } from './git.js' +import { tools as terminalTools } from './terminal.js' +import { tools as interactTools } from './interact.js' +import { tools as userTools } from './user.js' +import { tools as search } from './search.js' +//import { tools as webTools } from './web.js' +import { tools as memoryTools } from './memory.js' +// import { tools as emailTools } from './email' + +export const tools = { + fs: fsTools, + npm: npmTools, + git: gitTools, + terminal: terminalTools, + interact: interactTools, + user: userTools, + search: search, + // web: webTools, + memory: memoryTools + // email: emailTools +} diff --git a/packages/kbot/src/ai-tools/lib/tools/user.ts b/packages/kbot/src/ai-tools/lib/tools/user.ts new file mode 100644 index 00000000..6475ba88 --- /dev/null +++ b/packages/kbot/src/ai-tools/lib/tools/user.ts @@ -0,0 +1,83 @@ + +import { parse, join } from 'path' +import { RunnableToolFunction } from 'openai/lib/RunnableFunction' +import { sync as write } from '@polymech/fs/write' +import * as fs from 'fs' +import { lookup } from 'mime-types' +import { IKBotTask } from '../../types.js' +import { toolLogger } from '../../index.js' + +export const mime = (file: string = '') => parse(file).ext ? lookup(file) : null + +//const screenshot = require('screenshot-desktop') + +export const fileToBase64 = (filePath: string): string | null => { + try { + const fileBuffer = fs.readFileSync(filePath) + const mimeType = lookup(filePath) + if (!mimeType) { + throw new Error('Unable to determine MIME type.') + } + const base64Data = fileBuffer.toString('base64') + return `data:${mimeType};base64,${base64Data}` + } catch (error) { + console.error('fileToBase64 : Error reading file:', error) + return null + } +} +export const tools = (target: string, options: IKBotTask): Array => { + const logger = toolLogger('user', options) + return [ + { + type: 'function', + function: { + name: 'capture_screen', + description: 'Capture a screenshot and store it as file (jpg). Returns the path to the file', + parameters: { + type: 'object', + properties: { + file: { type: 'string' } + }, + required: ['file'] + }, + function: async (params: any) => { + try { + const outputPath = join(target, params.file) + const takeScreenshot = async () : Promise => { + /* + return new Promise((resolve, reject) => { + screenshot({ format: 'jpg' }).then((img) => { + write(outputPath, img) + resolve({ success: true, path: outputPath}) + }).catch(reject) + }) + */ + } + const { path } = await takeScreenshot() + return { + "role": "user", + "content": + [ + /* + { + type: "image_url", + image_url: { + url: fileToBase64( path), + } + } + */ + ] + } + } catch (error: any) { + logger.error('Error capturing screenshot:', error); + return { + success: false, + error: error.message + }; + } + }, + parse: JSON.parse + } + } as RunnableToolFunction + ]; +}; \ No newline at end of file diff --git a/packages/kbot/src/ai-tools/lib/tools/web.ts b/packages/kbot/src/ai-tools/lib/tools/web.ts new file mode 100644 index 00000000..44ca15a4 --- /dev/null +++ b/packages/kbot/src/ai-tools/lib/tools/web.ts @@ -0,0 +1,112 @@ +import * as path from 'path' +import { RunnableToolFunction } from 'openai/lib/RunnableFunction' + +import puppeteer from 'puppeteer' +import TurndownService from 'turndown' + +import { toolLogger } from '../../index.js' +import { IKBotTask } from '../../types.js' + +const turndown = new TurndownService() + +export const tools = (target: string, options: IKBotTask): Array => { + const logger = toolLogger('web', options) + return [ + { + type: 'function', + function: { + name: 'browse_page', + description: 'Browse a webpage and return its content as markdown, all links, images and pages main image', + parameters: { + type: 'object', + properties: { + url: { + type: 'string', + description: 'URL of the webpage to browse' + } + }, + required: ['url'] + }, + function: async (params: any) => { + try { + logger.debug(`Tool::BrowsePage Browsing ${params.url}`); + const browser = await puppeteer.launch({ + headless: true, + args: ['--no-sandbox', '--disable-setuid-sandbox'] + }) + + try { + const page = await browser.newPage() + logger.debug(`Tool::Web::BrowsePage Opening page ${params.url}`) + await page.goto(params.url, { + waitUntil: 'networkidle2' + }) + + const pageData = await page.evaluate((selector) => { + const elementsToRemove = document.querySelectorAll( + 'script, style, link, meta, noscript, iframe, [style*="display:none"],[style*="display: none"], .hidden' + ) + elementsToRemove.forEach(el => el.remove()) + + const links = Array.from(document.querySelectorAll('a')) + .map(a => ({ + text: a.textContent?.trim() || '', + href: a.href + })) + .filter(link => link.href && link.href.startsWith('http')) + .slice(0, 20) + + const images = Array.from(document.querySelectorAll('img')) + .map(img => ({ + src: img.src, + alt: img.alt || '', + width: img.width, + height: img.height + })) + .filter(img => img.src && img.src.startsWith('http')) + .slice(0, 20) + + const mainImage = document.querySelector('meta[property="og:image"]')?.getAttribute('content') || + document.querySelector('meta[name="og:image"]')?.getAttribute('content') + + let content + const body = document.body + content = body ? body.innerHTML : '' + return { + content, + links, + images, + ogImage: mainImage + } + }, null) + + const markdown = turndown.turndown(pageData.content) + await browser.close() + const ret = { + success: true, + markdown: markdown, + links: pageData.links, + images: pageData.images, + mainImage: pageData.ogImage, + url: params.url + }; + return ret + } catch (error: any) { + logger.debug('Error browsing page:', error.message, error); + await browser.close() + throw error + } + } catch (error: any) { + logger.debug('Error browsing page:', error.message); + return { + success: false, + error: error.message, + url: params.url + }; + } + }, + parse: JSON.parse + } + } as RunnableToolFunction + ] +} \ No newline at end of file diff --git a/packages/kbot/src/ai-tools/list.ts b/packages/kbot/src/ai-tools/list.ts new file mode 100644 index 00000000..7a394519 --- /dev/null +++ b/packages/kbot/src/ai-tools/list.ts @@ -0,0 +1,75 @@ +import type { Argv } from 'yargs' +import { tools } from '../lib/tools/tools.js' +import { logger } from '../index.js' +import { ListCommandSchema } from '../zod_schemas.js' +import { sync as write } from '@polymech/fs/write' +import { toYargs } from '@polymech/commons/schemas' + +export const options = (yargs: Argv) => toYargs(yargs, ListCommandSchema) + +interface FSParameters { + type: string; + properties: Record; + required: string[]; +} +interface FSDefinition { + name: string; + description: string; + category: string; + parameters: FSParameters; +} +interface FSData { + fs: FSDefinition[]; +} + +export const signature = (definition: FSDefinition): string => { + const { properties } = definition.parameters; + const requiredKeys = definition.parameters.required || []; + const params = Object.entries(properties).map(([key, val]) => { + const isRequired = requiredKeys.includes(key); + const isOptional = !!val.optional || !isRequired; + return isOptional ? `?${key}` : key; + }); + return `(${params.join(", ")})`; +} + +export function format(category: string, data: any): string { + const lines: string[] = [`## ${category}\n`]; + data.forEach(definition => { + const functionName = definition.name + const args = `${signature(definition)}` + const summary = definition.description + lines.push(`- ${functionName}${args}: ${summary}`) + }) + return lines.join("\n") +} + +export const list = async (argv: any, options?: any) => { + const getCategorizedTools = (category, options) => { + const toolsArray = tools[category](process.cwd(), options); + return toolsArray.map(tool => ({ + name: tool.function.name, + description: tool.function.description, + category, + parameters: tool.function.parameters + })); + } + const toolsList = { + email: getCategorizedTools('email', options), + search: getCategorizedTools('search', options), + interact: getCategorizedTools('email', options), + fs: getCategorizedTools('fs', options), + npm: getCategorizedTools('npm', options), + git: getCategorizedTools('git', options), + terminal: getCategorizedTools('terminal', options) + } + //write(argv.output + '.json', Object.keys(toolsList).map((k,v)=>format(k,v as any)).join('\n') ); + + const shortDescription = Object.keys(toolsList).map((value:string) => { + return format(value,toolsList[value]) + }).join('\n\n'); + if (argv.output) { + write(argv.output, JSON.stringify(toolsList, null, 2)) + write(argv.output + '.md', shortDescription) + } +} \ No newline at end of file diff --git a/packages/kbot/src/ai-tools/main.ts b/packages/kbot/src/ai-tools/main.ts new file mode 100644 index 00000000..42769abd --- /dev/null +++ b/packages/kbot/src/ai-tools/main.ts @@ -0,0 +1,16 @@ +#!/usr/bin/env node +import { commands } from './commands/index.js' +import { logger } from './index.js' +import cli from 'yargs' +import { hideBin } from 'yargs/helpers' +const yargs = cli(hideBin(process.argv)) + +async function main() { + try { + const argv = await commands(yargs).argv + } catch (error) { + logger.error('Error executing command:', error); + process.exit(1); + } +} +main() \ No newline at end of file diff --git a/packages/kbot/src/ai-tools/types.ts b/packages/kbot/src/ai-tools/types.ts new file mode 100644 index 00000000..9488d70d --- /dev/null +++ b/packages/kbot/src/ai-tools/types.ts @@ -0,0 +1,30 @@ +import { ChatCompletion, ChatCompletionMessage, ChatCompletionMessageParam } from 'openai/resources' +import { IKBotOptions } from './types_kbot.js' +import OpenAI from 'openai' +import { Logger, ILogObj } from 'tslog' + +import { RunnableFunctionWithParse } from 'openai/lib/RunnableFunction' + +export type onToolBefore = (ctx: RunnableFunctionWithParse,args: any) => Promise +export type onToolAfter = (ctx: RunnableFunctionWithParse, args: any, result?: any) => Promise + +export interface ICollector { + //OpenAI + onMessage: (message: ChatCompletionMessageParam) => void + onToolCall: (tool: ChatCompletionMessage.FunctionCall) => void, + onFunctionCallResult: (content: string) => void, + onChatCompletion: (completion: ChatCompletion) => void, + onContent: (content:string) => void, + // internal + onTool: (category: string, name: string, args: any, result?: any) => void + onToolBefore: onToolBefore + onToolAfter: onToolAfter +} +export interface IKBotTask extends IKBotOptions +{ + client?: OpenAI + collector?: ICollector + onRun?:(ctx: IKBotTask) => Promise + logger?: Logger + customTools?: any[] +} \ No newline at end of file diff --git a/packages/kbot/src/ai-tools/types_kbot.ts b/packages/kbot/src/ai-tools/types_kbot.ts new file mode 100644 index 00000000..86ce411d --- /dev/null +++ b/packages/kbot/src/ai-tools/types_kbot.ts @@ -0,0 +1,569 @@ +export interface IKBotOptions { + /** Target directory */ + path?: string; + /** The prompt. Supports file paths and environment variables. */ + prompt?: string | undefined; + /** Optional output path for modified files (Tool mode only) */ + output?: string | undefined; + /** Optional destination path for the result, will substitute ${MODEL_NAME} and ${ROUTER} in the path. Optional, used for "completion" mode */ + dst?: string | undefined; + /** How to handle output if --dst file already exists: "concat" (append) or "merge" (try to merge structures if possible, otherwise append). Only used if --dst is specified. */ + append?: ("concat" | "merge" | "replace") | undefined; + /** Specify how to wrap the output, "meta (file name, absolute path, cwd)" or "none". */ + wrap?: "meta" | "none"; + /** Iterate over items, supported: GLOB | Path to JSON File | array of strings (comma separated). To test different models, use --each="gpt-3.5-turbo,gpt-4o", the actual string will exposed as variable `ITEM`, eg: --dst="${ITEM}-output.md" */ + each?: string | undefined; + /** Disable tools categories, eg: --disable=fs,git,interact,terminal,search,web,email,user */ + disable?: string[]; + /** List of specific tools to disable */ + disableTools?: string[]; + /** List of tools to use. Can be built-in tool names or paths to custom tool files. Default: fs,git,interact,terminal,search,web,email,user */ + tools?: (string[] | string); + /** Comma separated glob patterns or paths, eg --include=src/*.tsx,src/*.ts --include=package.json */ + include?: string[] | undefined; + /** Comma separated glob patterns or paths, eg --exclude=src/*.tsx,src/*.ts --exclude=package.json */ + exclude?: string[] | undefined; + /** Specify a glob extension behavior. Available presets: match-cpp. Also accepts a custom glob pattern with variables like ${SRC_DIR}, ${SRC_NAME}, ${SRC_EXT}. E.g., "match-cpp" or "${SRC_DIR}/${SRC_NAME}*.cpp" */ + globExtension?: (("match-cpp") | string) | undefined; + /** Explicit API key to use */ + api_key?: string | undefined; + /** AI model to use for processing. Available models: +  +  OpenRouter models: +  + ai21/jamba-large-1.7 | paid + aion-labs/aion-1.0 | paid + aion-labs/aion-1.0-mini | paid + aion-labs/aion-2.0 | paid + aion-labs/aion-rp-llama-3.1-8b | paid + alfredpros/codellama-7b-instruct-solidity | paid + allenai/molmo-2-8b | paid + allenai/olmo-2-0325-32b-instruct | paid + allenai/olmo-3-32b-think | paid + allenai/olmo-3-7b-instruct | paid + allenai/olmo-3-7b-think | paid + allenai/olmo-3.1-32b-instruct | paid + allenai/olmo-3.1-32b-think | paid + amazon/nova-2-lite-v1 | paid + amazon/nova-lite-v1 | paid + amazon/nova-micro-v1 | paid + amazon/nova-premier-v1 | paid + amazon/nova-pro-v1 | paid + anthropic/claude-3-haiku | paid + anthropic/claude-3.5-haiku | paid + anthropic/claude-3.5-sonnet | paid + anthropic/claude-3.7-sonnet | paid + anthropic/claude-3.7-sonnet:thinking | paid + anthropic/claude-haiku-4.5 | paid + anthropic/claude-opus-4 | paid + anthropic/claude-opus-4.1 | paid + anthropic/claude-opus-4.5 | paid + anthropic/claude-opus-4.6 | paid + anthropic/claude-sonnet-4 | paid + anthropic/claude-sonnet-4.5 | paid + anthropic/claude-sonnet-4.6 | paid + arcee-ai/coder-large | paid + arcee-ai/maestro-reasoning | paid + arcee-ai/spotlight | paid + arcee-ai/trinity-large-preview:free | free + arcee-ai/trinity-mini | paid + arcee-ai/trinity-mini:free | free + arcee-ai/virtuoso-large | paid + openrouter/auto | paid + baidu/ernie-4.5-21b-a3b | paid + baidu/ernie-4.5-21b-a3b-thinking | paid + baidu/ernie-4.5-300b-a47b | paid + baidu/ernie-4.5-vl-28b-a3b | paid + baidu/ernie-4.5-vl-424b-a47b | paid + openrouter/bodybuilder | paid + bytedance-seed/seed-1.6 | paid + bytedance-seed/seed-1.6-flash | paid + bytedance-seed/seed-2.0-lite | paid + bytedance-seed/seed-2.0-mini | paid + bytedance/ui-tars-1.5-7b | paid + cohere/command-a | paid + cohere/command-r-08-2024 | paid + cohere/command-r-plus-08-2024 | paid + cohere/command-r7b-12-2024 | paid + deepcogito/cogito-v2.1-671b | paid + deepseek/deepseek-chat | paid + deepseek/deepseek-chat-v3-0324 | paid + deepseek/deepseek-chat-v3.1 | paid + deepseek/deepseek-v3.1-terminus | paid + deepseek/deepseek-v3.2 | paid + deepseek/deepseek-v3.2-exp | paid + deepseek/deepseek-v3.2-speciale | paid + deepseek/deepseek-r1 | paid + deepseek/deepseek-r1-0528 | paid + deepseek/deepseek-r1-distill-llama-70b | paid + deepseek/deepseek-r1-distill-qwen-32b | paid + eleutherai/llemma_7b | paid + essentialai/rnj-1-instruct | paid + openrouter/free | paid + alpindale/goliath-120b | paid + google/gemini-2.0-flash-001 | paid + google/gemini-2.0-flash-lite-001 | paid + google/gemini-2.5-flash | paid + google/gemini-2.5-flash-lite | paid + google/gemini-2.5-flash-lite-preview-09-2025 | paid + google/gemini-2.5-pro | paid + google/gemini-2.5-pro-preview-05-06 | paid + google/gemini-2.5-pro-preview | paid + google/gemini-3-flash-preview | paid + google/gemini-3-pro-preview | paid + google/gemini-3.1-flash-lite-preview | paid + google/gemini-3.1-pro-preview | paid + google/gemini-3.1-pro-preview-customtools | paid + google/gemma-2-27b-it | paid + google/gemma-2-9b-it | paid + google/gemma-3-12b-it | paid + google/gemma-3-12b-it:free | free + google/gemma-3-27b-it | paid + google/gemma-3-27b-it:free | free + google/gemma-3-4b-it | paid + google/gemma-3-4b-it:free | free + google/gemma-3n-e2b-it:free | free + google/gemma-3n-e4b-it | paid + google/gemma-3n-e4b-it:free | free + google/gemini-2.5-flash-image | paid + google/gemini-3.1-flash-image-preview | paid + google/gemini-3-pro-image-preview | paid + ibm-granite/granite-4.0-h-micro | paid + inception/mercury | paid + inception/mercury-2 | paid + inception/mercury-coder | paid + inflection/inflection-3-pi | paid + inflection/inflection-3-productivity | paid + kwaipilot/kat-coder-pro | paid + liquid/lfm-2.2-6b | paid + liquid/lfm-2-24b-a2b | paid + liquid/lfm2-8b-a1b | paid + liquid/lfm-2.5-1.2b-instruct:free | free + liquid/lfm-2.5-1.2b-thinking:free | free + meta-llama/llama-guard-3-8b | paid + anthracite-org/magnum-v4-72b | paid + mancer/weaver | paid + meituan/longcat-flash-chat | paid + meta-llama/llama-3-70b-instruct | paid + meta-llama/llama-3-8b-instruct | paid + meta-llama/llama-3.1-405b | paid + meta-llama/llama-3.1-70b-instruct | paid + meta-llama/llama-3.1-8b-instruct | paid + meta-llama/llama-3.2-11b-vision-instruct | paid + meta-llama/llama-3.2-1b-instruct | paid + meta-llama/llama-3.2-3b-instruct | paid + meta-llama/llama-3.2-3b-instruct:free | free + meta-llama/llama-3.3-70b-instruct | paid + meta-llama/llama-3.3-70b-instruct:free | free + meta-llama/llama-4-maverick | paid + meta-llama/llama-4-scout | paid + meta-llama/llama-guard-4-12b | paid + microsoft/phi-4 | paid + minimax/minimax-m1 | paid + minimax/minimax-m2 | paid + minimax/minimax-m2-her | paid + minimax/minimax-m2.1 | paid + minimax/minimax-m2.5 | paid + minimax/minimax-m2.5:free | free + minimax/minimax-m2.7 | paid + minimax/minimax-01 | paid + mistralai/mistral-large | paid + mistralai/mistral-large-2407 | paid + mistralai/mistral-large-2411 | paid + mistralai/codestral-2508 | paid + mistralai/devstral-2512 | paid + mistralai/devstral-medium | paid + mistralai/devstral-small | paid + mistralai/ministral-14b-2512 | paid + mistralai/ministral-3b-2512 | paid + mistralai/ministral-8b-2512 | paid + mistralai/mistral-7b-instruct-v0.1 | paid + mistralai/mistral-large-2512 | paid + mistralai/mistral-medium-3 | paid + mistralai/mistral-medium-3.1 | paid + mistralai/mistral-nemo | paid + mistralai/mistral-small-24b-instruct-2501 | paid + mistralai/mistral-small-3.1-24b-instruct | paid + mistralai/mistral-small-3.1-24b-instruct:free | free + mistralai/mistral-small-3.2-24b-instruct | paid + mistralai/mistral-small-2603 | paid + mistralai/mistral-small-creative | paid + mistralai/mixtral-8x22b-instruct | paid + mistralai/mixtral-8x7b-instruct | paid + mistralai/pixtral-large-2411 | paid + mistralai/mistral-saba | paid + mistralai/voxtral-small-24b-2507 | paid + moonshotai/kimi-k2 | paid + moonshotai/kimi-k2-0905 | paid + moonshotai/kimi-k2-thinking | paid + moonshotai/kimi-k2.5 | paid + morph/morph-v3-fast | paid + morph/morph-v3-large | paid + gryphe/mythomax-l2-13b | paid + nex-agi/deepseek-v3.1-nex-n1 | paid + nousresearch/hermes-3-llama-3.1-405b | paid + nousresearch/hermes-3-llama-3.1-405b:free | free + nousresearch/hermes-3-llama-3.1-70b | paid + nousresearch/hermes-4-405b | paid + nousresearch/hermes-4-70b | paid + nousresearch/hermes-2-pro-llama-3-8b | paid + nvidia/llama-3.1-nemotron-70b-instruct | paid + nvidia/llama-3.3-nemotron-super-49b-v1.5 | paid + nvidia/nemotron-3-nano-30b-a3b | paid + nvidia/nemotron-3-nano-30b-a3b:free | free + nvidia/nemotron-3-super-120b-a12b | paid + nvidia/nemotron-3-super-120b-a12b:free | free + nvidia/nemotron-nano-12b-v2-vl | paid + nvidia/nemotron-nano-12b-v2-vl:free | free + nvidia/nemotron-nano-9b-v2 | paid + nvidia/nemotron-nano-9b-v2:free | free + openai/gpt-audio | paid + openai/gpt-audio-mini | paid + openai/gpt-3.5-turbo | paid + openai/gpt-3.5-turbo-0613 | paid + openai/gpt-3.5-turbo-16k | paid + openai/gpt-3.5-turbo-instruct | paid + openai/gpt-4 | paid + openai/gpt-4-0314 | paid + openai/gpt-4-turbo | paid + openai/gpt-4-1106-preview | paid + openai/gpt-4-turbo-preview | paid + openai/gpt-4.1 | paid + openai/gpt-4.1-mini | paid + openai/gpt-4.1-nano | paid + openai/gpt-4o | paid + openai/gpt-4o-2024-05-13 | paid + openai/gpt-4o-2024-08-06 | paid + openai/gpt-4o-2024-11-20 | paid + openai/gpt-4o:extended | paid + openai/gpt-4o-audio-preview | paid + openai/gpt-4o-search-preview | paid + openai/gpt-4o-mini | paid + openai/gpt-4o-mini-2024-07-18 | paid + openai/gpt-4o-mini-search-preview | paid + openai/gpt-5 | paid + openai/gpt-5-chat | paid + openai/gpt-5-codex | paid + openai/gpt-5-image | paid + openai/gpt-5-image-mini | paid + openai/gpt-5-mini | paid + openai/gpt-5-nano | paid + openai/gpt-5-pro | paid + openai/gpt-5.1 | paid + openai/gpt-5.1-chat | paid + openai/gpt-5.1-codex | paid + openai/gpt-5.1-codex-max | paid + openai/gpt-5.1-codex-mini | paid + openai/gpt-5.2 | paid + openai/gpt-5.2-chat | paid + openai/gpt-5.2-pro | paid + openai/gpt-5.2-codex | paid + openai/gpt-5.3-chat | paid + openai/gpt-5.3-codex | paid + openai/gpt-5.4 | paid + openai/gpt-5.4-mini | paid + openai/gpt-5.4-nano | paid + openai/gpt-5.4-pro | paid + openai/gpt-oss-120b | paid + openai/gpt-oss-120b:free | free + openai/gpt-oss-20b | paid + openai/gpt-oss-20b:free | free + openai/gpt-oss-safeguard-20b | paid + openai/o1 | paid + openai/o1-pro | paid + openai/o3 | paid + openai/o3-deep-research | paid + openai/o3-mini | paid + openai/o3-mini-high | paid + openai/o3-pro | paid + openai/o4-mini | paid + openai/o4-mini-deep-research | paid + openai/o4-mini-high | paid + perplexity/sonar | paid + perplexity/sonar-deep-research | paid + perplexity/sonar-pro | paid + perplexity/sonar-pro-search | paid + perplexity/sonar-reasoning-pro | paid + prime-intellect/intellect-3 | paid + qwen/qwen-plus-2025-07-28 | paid + qwen/qwen-plus-2025-07-28:thinking | paid + qwen/qwen-vl-max | paid + qwen/qwen-vl-plus | paid + qwen/qwen-max | paid + qwen/qwen-plus | paid + qwen/qwen-turbo | paid + qwen/qwen-2.5-7b-instruct | paid + qwen/qwen2.5-coder-7b-instruct | paid + qwen/qwen2.5-vl-32b-instruct | paid + qwen/qwen2.5-vl-72b-instruct | paid + qwen/qwen-2.5-vl-7b-instruct | paid + qwen/qwen3-14b | paid + qwen/qwen3-235b-a22b | paid + qwen/qwen3-235b-a22b-2507 | paid + qwen/qwen3-235b-a22b-thinking-2507 | paid + qwen/qwen3-30b-a3b | paid + qwen/qwen3-30b-a3b-instruct-2507 | paid + qwen/qwen3-30b-a3b-thinking-2507 | paid + qwen/qwen3-32b | paid + qwen/qwen3-4b:free | free + qwen/qwen3-8b | paid + qwen/qwen3-coder-30b-a3b-instruct | paid + qwen/qwen3-coder | paid + qwen/qwen3-coder:free | free + qwen/qwen3-coder-flash | paid + qwen/qwen3-coder-next | paid + qwen/qwen3-coder-plus | paid + qwen/qwen3-max | paid + qwen/qwen3-max-thinking | paid + qwen/qwen3-next-80b-a3b-instruct | paid + qwen/qwen3-next-80b-a3b-instruct:free | free + qwen/qwen3-next-80b-a3b-thinking | paid + qwen/qwen3-vl-235b-a22b-instruct | paid + qwen/qwen3-vl-235b-a22b-thinking | paid + qwen/qwen3-vl-30b-a3b-instruct | paid + qwen/qwen3-vl-30b-a3b-thinking | paid + qwen/qwen3-vl-32b-instruct | paid + qwen/qwen3-vl-8b-instruct | paid + qwen/qwen3-vl-8b-thinking | paid + qwen/qwen3.5-397b-a17b | paid + qwen/qwen3.5-plus-02-15 | paid + qwen/qwen3.5-122b-a10b | paid + qwen/qwen3.5-27b | paid + qwen/qwen3.5-35b-a3b | paid + qwen/qwen3.5-9b | paid + qwen/qwen3.5-flash-02-23 | paid + qwen/qwq-32b | paid + qwen/qwen-2.5-72b-instruct | paid + qwen/qwen-2.5-coder-32b-instruct | paid + relace/relace-apply-3 | paid + relace/relace-search | paid + undi95/remm-slerp-l2-13b | paid + sao10k/l3-lunaris-8b | paid + sao10k/l3-euryale-70b | paid + sao10k/l3.1-70b-hanami-x1 | paid + sao10k/l3.1-euryale-70b | paid + sao10k/l3.3-euryale-70b | paid + stepfun/step-3.5-flash | paid + stepfun/step-3.5-flash:free | free + switchpoint/router | paid + tencent/hunyuan-a13b-instruct | paid + thedrummer/cydonia-24b-v4.1 | paid + thedrummer/rocinante-12b | paid + thedrummer/skyfall-36b-v2 | paid + thedrummer/unslopnemo-12b | paid + tngtech/deepseek-r1t2-chimera | paid + alibaba/tongyi-deepresearch-30b-a3b | paid + upstage/solar-pro-3 | paid + cognitivecomputations/dolphin-mistral-24b-venice-edition:free | free + microsoft/wizardlm-2-8x22b | paid + writer/palmyra-x5 | paid + x-ai/grok-3 | paid + x-ai/grok-3-beta | paid + x-ai/grok-3-mini | paid + x-ai/grok-3-mini-beta | paid + x-ai/grok-4 | paid + x-ai/grok-4-fast | paid + x-ai/grok-4.1-fast | paid + x-ai/grok-4.20-beta | paid + x-ai/grok-4.20-multi-agent-beta | paid + x-ai/grok-code-fast-1 | paid + xiaomi/mimo-v2-flash | paid + xiaomi/mimo-v2-omni | paid + xiaomi/mimo-v2-pro | paid + z-ai/glm-4-32b | paid + z-ai/glm-4.5 | paid + z-ai/glm-4.5-air | paid + z-ai/glm-4.5-air:free | free + z-ai/glm-4.5v | paid + z-ai/glm-4.6 | paid + z-ai/glm-4.6v | paid + z-ai/glm-4.7 | paid + z-ai/glm-4.7-flash | paid + z-ai/glm-5 | paid + z-ai/glm-5-turbo | paid +  +  OpenAI models: +  + babbage-002 + chatgpt-image-latest + dall-e-2 + dall-e-3 + davinci-002 + gpt-3.5-turbo + gpt-3.5-turbo-0125 + gpt-3.5-turbo-1106 + gpt-3.5-turbo-16k + gpt-3.5-turbo-instruct + gpt-3.5-turbo-instruct-0914 + gpt-4 + gpt-4-0125-preview + gpt-4-0613 + gpt-4-1106-preview + gpt-4-turbo + gpt-4-turbo-2024-04-09 + gpt-4-turbo-preview + gpt-4.1 + gpt-4.1-2025-04-14 + gpt-4.1-mini + gpt-4.1-mini-2025-04-14 + gpt-4.1-nano + gpt-4.1-nano-2025-04-14 + gpt-4o + gpt-4o-2024-05-13 + gpt-4o-2024-08-06 + gpt-4o-2024-11-20 + gpt-4o-audio-preview + gpt-4o-audio-preview-2024-12-17 + gpt-4o-audio-preview-2025-06-03 + gpt-4o-mini + gpt-4o-mini-2024-07-18 + gpt-4o-mini-audio-preview + gpt-4o-mini-audio-preview-2024-12-17 + gpt-4o-mini-realtime-preview + gpt-4o-mini-realtime-preview-2024-12-17 + gpt-4o-mini-search-preview + gpt-4o-mini-search-preview-2025-03-11 + gpt-4o-mini-transcribe + gpt-4o-mini-transcribe-2025-03-20 + gpt-4o-mini-transcribe-2025-12-15 + gpt-4o-mini-tts + gpt-4o-mini-tts-2025-03-20 + gpt-4o-mini-tts-2025-12-15 + gpt-4o-realtime-preview + gpt-4o-realtime-preview-2024-12-17 + gpt-4o-realtime-preview-2025-06-03 + gpt-4o-search-preview + gpt-4o-search-preview-2025-03-11 + gpt-4o-transcribe + gpt-4o-transcribe-diarize + gpt-5 + gpt-5-2025-08-07 + gpt-5-chat-latest + gpt-5-codex + gpt-5-mini + gpt-5-mini-2025-08-07 + gpt-5-nano + gpt-5-nano-2025-08-07 + gpt-5-pro + gpt-5-pro-2025-10-06 + gpt-5-search-api + gpt-5-search-api-2025-10-14 + gpt-5.1 + gpt-5.1-2025-11-13 + gpt-5.1-chat-latest + gpt-5.1-codex + gpt-5.1-codex-max + gpt-5.1-codex-mini + gpt-5.2 + gpt-5.2-2025-12-11 + gpt-5.2-chat-latest + gpt-5.2-codex + gpt-5.2-pro + gpt-5.2-pro-2025-12-11 + gpt-5.3-chat-latest + gpt-5.3-codex + gpt-5.4 + gpt-5.4-2026-03-05 + gpt-5.4-mini + gpt-5.4-mini-2026-03-17 + gpt-5.4-nano + gpt-5.4-nano-2026-03-17 + gpt-5.4-pro + gpt-5.4-pro-2026-03-05 + gpt-audio + gpt-audio-1.5 + gpt-audio-2025-08-28 + gpt-audio-mini + gpt-audio-mini-2025-10-06 + gpt-audio-mini-2025-12-15 + gpt-image-1 + gpt-image-1-mini + gpt-image-1.5 + gpt-realtime + gpt-realtime-1.5 + gpt-realtime-2025-08-28 + gpt-realtime-mini + gpt-realtime-mini-2025-10-06 + gpt-realtime-mini-2025-12-15 + o1 + o1-2024-12-17 + o1-pro + o1-pro-2025-03-19 + o3 + o3-2025-04-16 + o3-mini + o3-mini-2025-01-31 + o4-mini + o4-mini-2025-04-16 + o4-mini-deep-research + o4-mini-deep-research-2025-06-26 + omni-moderation-2024-09-26 + omni-moderation-latest + sora-2 + sora-2-pro + text-embedding-3-large + text-embedding-3-small + text-embedding-ada-002 + tts-1 + tts-1-1106 + tts-1-hd + tts-1-hd-1106 + whisper-1 + ----- + +  +  Deepseek models: +  + deepseek-chat + deepseek-reasoner + ----- + */ + model?: string | undefined; + /** Router to use: openai, openrouter or deepseek */ + router?: string; + /** Chat completion mode: + completion, tools, assistant. + completion: no support for tools, please use --dst parameter to save the output. + tools: allows for tools to be used, eg 'save to ./output.md'. Not all models support this mode. + responses: allows for responses to be used, eg 'save to ./output.md'. Not all models support this mode. + assistant: : allows documents (PDF, DOCX, ...) to be added but dont support tools. Use --dst to save the output. Supported files : + custom: custom mode + */ + mode?: "completion" | "tools" | "assistant" | "responses" | "custom"; + /** Logging level for the application */ + logLevel?: number; + /** Path to profile for variables. Supports environment variables. */ + profile?: string | undefined; + /** Base URL for the API, set via --router or directly */ + baseURL?: string | undefined; + /** Path to JSON configuration file (API keys). Supports environment variables. */ + config?: string | undefined; + /** Create a script */ + dump?: string | undefined; + /** Path to preferences file, eg: location, your email address, gender, etc. Supports environment variables. */ + preferences?: string; + /** Logging directory */ + logs?: string; + /** Enable streaming (verbose LLM output) */ + stream?: boolean; + /** Use alternate tokenizer & instead of $ */ + alt?: boolean; + /** Environment (in profile) */ + env?: string; + variables?: { + [x: string]: string; + }; + /** List of filters to apply to the output. + Used only in completion mode and a given output file specified with --dst. + It unwraps by default any code or data in Markdown. + Choices: + JSON,JSONUnescape,JSONPretty,AlphaSort,code,JSONParse,trim,markdown + */ + filters?: (string | ("JSON" | "JSONUnescape" | "JSONPretty" | "AlphaSort" | "code" | "JSONParse" | "trim" | "markdown")[] | string[] | ((...args_0: unknown[]) => unknown)[]); + /** JSONPath query to be used to transform input objects */ + query?: (string | null); + /** Dry run - only write out parameters without making API calls */ + dry?: (boolean | string); + /** Format for structured outputs. Can be a Zod schema, a Zod schema string, a JSON schema string, or a path to a JSON file. */ + format?: (string | any) | undefined; +} \ No newline at end of file diff --git a/packages/kbot/src/ai-tools/zod_schemas.ts b/packages/kbot/src/ai-tools/zod_schemas.ts new file mode 100644 index 00000000..ebca5582 --- /dev/null +++ b/packages/kbot/src/ai-tools/zod_schemas.ts @@ -0,0 +1,75 @@ +import { z } from 'zod'; + +/** Schema for listing files in a directory */ +export const FileListingOptionsSchema = z.object({ + directory: z.string().describe('Directory path to list files from'), + pattern: z.string().optional().describe('Glob pattern for filtering files') +}).describe('IFileListingOptions') + +/** Schema for file removal operations */ +export const FileRemovalOptionsSchema = z.object({ + path: z.string().describe('Path of the file to remove') +}).describe('IFileRemovalOptions'); + +/** Schema for git commit operations */ +export const GitCommitSchema = z.object({ + files: z.array(z.string()).describe('Files to commit'), + message: z.string().describe('Commit message') +}).describe('IGitCommitOptions'); + +/** Schema for git revert operations */ +export const GitRevertSchema = z.object({ + files: z.array(z.string()).describe('Files to revert') +}).describe('IGitRevertOptions'); + +/** Schema for git version switch operations */ +export const GitSwitchVersionSchema = z.object({ + branch: z.string().describe('Branch name to switch to'), + remote: z.string().default('origin').describe('Remote name') +}).describe('IGitSwitchVersionOptions'); + +/** Schema for git raw file retrieval */ +export const GitRawFileSchema = z.object({ + url: z.string().optional().describe('Full GitHub raw URL'), + repo: z.string().optional().describe('Repository in format owner/repo'), + path: z.string().optional().describe('File path within repository') +}).refine( + data => (data.url) || (data.repo && data.path), + 'Either url or both repo and path must be provided' +).describe('IGitRawFileOptions'); + +/** Schema for npm run command */ +export const NpmRunSchema = z.object({ + command: z.string().describe('Command to run (e.g. install, test, etc)'), + args: z.array(z.string()).optional().describe('Additional arguments for the command') +}).describe('INpmRunOptions'); + +/** Schema for terminal command execution */ +export const TerminalCommandSchema = z.object({ + command: z.string().describe('Command to execute'), + args: z.array(z.string()).optional().describe('Command arguments'), + cwd: z.string().optional().describe('Working directory for command execution'), + background: z.boolean().optional().describe('Run command in background (non-blocking)'), + window: z.boolean().optional().describe('Open command in new terminal window'), + detached: z.boolean().optional().describe('Run process detached from parent') +}).describe('ITerminalCommandOptions'); + +/** Schema for tool invocation parameters */ +export const InvokeToolSchema = z.object({ + tools: z.string().describe('Tool category to use (fs, npm, git, terminal)'), + function: z.string().describe('Function name to invoke'), + target: z.string().default(process.cwd()).describe('Target directory'), + params: z.string().optional().describe('JSON string of parameters'), + output: z.string().optional().describe('Path to write the output to'), + env_key: z.string().optional().describe('Environment configuration key') +}).describe('IInvokeToolOptions'); + +/** Schema for list command options */ +export const ListCommandSchema = z.object({ + output: z.string().default("./llm-tools.json").describe('Output file path for tools list') +}).describe('IListCommandOptions'); + +/** Schema for tool listing options */ +export const ToolListingOptionsSchema = z.object({ + output: z.string().default('./llm-tools.json').describe('Path to write the output to') +}).describe('IToolListingOptions'); \ No newline at end of file diff --git a/packages/kbot/src/ai-tools/zod_types.ts b/packages/kbot/src/ai-tools/zod_types.ts new file mode 100644 index 00000000..b2ea8a7a --- /dev/null +++ b/packages/kbot/src/ai-tools/zod_types.ts @@ -0,0 +1,68 @@ +export interface IFileListingOptions { + /** Directory path to list files from */ + directory: string; + /** Glob pattern for filtering files */ + pattern?: string | undefined; +} +export interface IFileRemovalOptions { + /** Path of the file to remove */ + path: string; +} +export interface IGitCommitOptions { + /** Files to commit */ + files: string[]; + /** Commit message */ + message: string; +} +export interface IGitRevertOptions { + /** Files to revert */ + files: string[]; +} +export interface IGitSwitchVersionOptions { + /** Branch name to switch to */ + branch: string; + /** Remote name */ + remote: string; +} +export interface IInvokeToolOptions { + /** Tool category to use (fs, npm, git, terminal) */ + tools: string; + /** Function name to invoke */ + function: string; + /** Target directory */ + target: string; + /** JSON string of parameters */ + params?: string | undefined; + /** Path to write the output to */ + output?: string | undefined; + /** Environment configuration key */ + env_key?: string | undefined; +} +export interface IToolListingOptions { + /** Path to write the output to */ + output: string; +} +export interface ITerminalCommandOptions { + /** Command to execute */ + command: string; + /** Command arguments */ + args?: string[] | undefined; + /** Working directory for command execution */ + cwd?: string | undefined; + /** Run command in background (non-blocking) */ + background?: boolean | undefined; + /** Open command in new terminal window */ + window?: boolean | undefined; + /** Run process detached from parent */ + detached?: boolean | undefined; +} +export interface IListCommandOptions { + /** Output file path for tools list */ + output: string; +} +export interface INpmRunOptions { + /** Command to run (e.g. install, test, etc) */ + command: string; + /** Additional arguments for the command */ + args?: string[] | undefined; +} \ No newline at end of file diff --git a/packages/kbot/tests/unit/ollama-basics.test.ts b/packages/kbot/tests/unit/ollama-basics.test.ts new file mode 100644 index 00000000..92bfc19c --- /dev/null +++ b/packages/kbot/tests/unit/ollama-basics.test.ts @@ -0,0 +1,251 @@ +import { describe, it, expect } from 'vitest' +import { sync as exists } from "@polymech/fs/exists" +import { z } from 'zod' + +import { + TEST_TIMEOUT, + TestResult, + runTest, + generateTestReport, + getReportPaths +} from './commons' +import { zodFunction } from '../../src/ai-tools/lib/tools/index.js' + +const models = ['qwen2.5:3b'] + +// --------------------------------------------------------------------------- +// Mock tool implementations +// --------------------------------------------------------------------------- + +const addTool = zodFunction({ + name: 'add', + description: 'Add two numbers together and return the sum.', + schema: z.object({ + a: z.number().describe('First number'), + b: z.number().describe('Second number'), + }), + function: async ({ a, b }) => ({ result: a + b }), +}) + +const multiplyTool = zodFunction({ + name: 'multiply', + description: 'Multiply two numbers and return the product.', + schema: z.object({ + a: z.number().describe('First number'), + b: z.number().describe('Second number'), + }), + function: async ({ a, b }) => ({ result: a * b }), +}) + +const getWeatherTool = zodFunction({ + name: 'get_weather', + description: 'Get the current weather for a city. Returns temperature in Celsius and a condition string.', + schema: z.object({ + city: z.string().describe('The city name to get weather for'), + }), + function: async ({ city }) => ({ + city, + temperature_c: 22, + condition: 'sunny', + }), +}) + +const formatNumberTool = zodFunction({ + name: 'format_number', + description: 'Format a number with thousand separators and optional decimal places.', + schema: z.object({ + value: z.number().describe('The number to format'), + decimals: z.number().optional().describe('Number of decimal places (default 2)'), + }), + function: async ({ value, decimals = 2 }) => ({ + formatted: value.toLocaleString('en-US', { minimumFractionDigits: decimals, maximumFractionDigits: decimals }), + }), +}) + +// --------------------------------------------------------------------------- +// Basic Ollama Operations +// --------------------------------------------------------------------------- + +describe('Ollama Basic Operations', () => { + let testResults: TestResult[] = [] + const TEST_LOG_PATH = getReportPaths('ollama-basics', 'json') + const TEST_REPORT_PATH = getReportPaths('ollama-basics', 'md') + + it.each(models)('should add two numbers with model %s', async (modelName) => { + const result = await runTest( + 'add 5 and 3. Return only the number, no explanation.', + '8', + 'addition', + modelName, + TEST_LOG_PATH, + 'completion', + { router: 'ollama' } + ) + testResults.push(result) + expect(result.result[0]?.trim()?.toLowerCase()).toEqual('8') + }, { timeout: TEST_TIMEOUT }) + + it.each(models)('should multiply two numbers with model %s', async (modelName) => { + const result = await runTest( + 'multiply 8 and 3. Return only the number, no explanation.', + '24', + 'multiplication', + modelName, + TEST_LOG_PATH, + 'completion', + { router: 'ollama' } + ) + testResults.push(result) + expect(result.result[0]?.trim()?.toLowerCase()).toEqual('24') + }, { timeout: TEST_TIMEOUT }) + + it.each(models)('should divide two numbers with model %s', async (modelName) => { + const result = await runTest( + 'divide 15 by 3. Return only the number, no explanation.', + '5', + 'division', + modelName, + TEST_LOG_PATH, + 'completion', + { router: 'ollama' } + ) + testResults.push(result) + expect(result.result[0]?.trim()?.toLowerCase()).toEqual('5') + }, { timeout: TEST_TIMEOUT }) + + it('should generate markdown report', () => { + generateTestReport(testResults, 'Ollama Basic Operations Test Results', TEST_REPORT_PATH) + expect(exists(TEST_REPORT_PATH) === 'file').toBe(true) + }) +}) + +// --------------------------------------------------------------------------- +// Custom Tool Call Quality +// --------------------------------------------------------------------------- + +describe('Ollama Custom Tool Call Quality', () => { + let testResults: TestResult[] = [] + const TEST_LOG_PATH = getReportPaths('ollama-tools', 'json') + const TEST_REPORT_PATH = getReportPaths('ollama-tools', 'md') + + it.each(models)( + 'should call add tool and return correct sum [%s]', + async (modelName) => { + const result = await runTest( + 'Use the add tool to add 17 and 25. Report back the result.', + '42', + 'tool-add', + modelName, + TEST_LOG_PATH, + 'tools', + { + router: 'ollama', + customTools: [addTool], + equalityCheck: 'llm_equal', + } + ) + testResults.push(result) + // Result must contain 42 + expect(result.result[0]).toMatch(/42/) + }, + { timeout: TEST_TIMEOUT } + ) + + it.each(models)( + 'should call multiply tool and return correct product [%s]', + async (modelName) => { + const result = await runTest( + 'Use the multiply tool to compute 6 times 7. Tell me the answer.', + '42', + 'tool-multiply', + modelName, + TEST_LOG_PATH, + 'tools', + { + router: 'ollama', + customTools: [multiplyTool], + equalityCheck: 'llm_equal', + } + ) + testResults.push(result) + expect(result.result[0]).toMatch(/42/) + }, + { timeout: TEST_TIMEOUT } + ) + + it.each(models)( + 'should call get_weather tool with correct city argument [%s]', + async (modelName) => { + const result = await runTest( + "What's the weather like in Paris? Use the get_weather tool.", + 'sunny', + 'tool-weather', + modelName, + TEST_LOG_PATH, + 'tools', + { + router: 'ollama', + customTools: [getWeatherTool], + equalityCheck: 'llm_equal', + } + ) + testResults.push(result) + // Response must mention the mocked condition "sunny" and/or 22°C + const lower = result.result[0]?.toLowerCase() ?? '' + expect(lower).toMatch(/sunny|22/) + }, + { timeout: TEST_TIMEOUT } + ) + + it.each(models)( + 'should select the correct tool from multiple available tools [%s]', + async (modelName) => { + const result = await runTest( + 'Use the appropriate tool to add 100 and 200.', + '300', + 'tool-selection', + modelName, + TEST_LOG_PATH, + 'tools', + { + router: 'ollama', + // Both tools available — model must pick add, not multiply + customTools: [addTool, multiplyTool, getWeatherTool], + equalityCheck: 'llm_equal', + } + ) + testResults.push(result) + expect(result.result[0]).toMatch(/300/) + }, + { timeout: TEST_TIMEOUT } + ) + + it.each(models)( + 'should chain two tool calls: multiply then format [%s]', + async (modelName) => { + const result = await runTest( + 'First multiply 123 by 456, then format the result with 2 decimal places.', + '56,088.00', + 'tool-chain', + modelName, + TEST_LOG_PATH, + 'tools', + { + router: 'ollama', + customTools: [multiplyTool, formatNumberTool], + equalityCheck: 'llm_equal', + } + ) + testResults.push(result) + // 123 * 456 = 56088 → formatted as 56,088.00 + expect(result.result[0]).toMatch(/56[,.]?088/) + }, + { timeout: TEST_TIMEOUT } + ) + + it('should generate tool quality markdown report', () => { + generateTestReport(testResults, 'Ollama Custom Tool Call Quality Results', TEST_REPORT_PATH) + expect(exists(TEST_REPORT_PATH) === 'file').toBe(true) + }) +}) + diff --git a/packages/kbot/tests/unit/reports/ollama-basics.json b/packages/kbot/tests/unit/reports/ollama-basics.json new file mode 100644 index 00000000..68ce100b --- /dev/null +++ b/packages/kbot/tests/unit/reports/ollama-basics.json @@ -0,0 +1,79 @@ +{ + "results": [ + { + "test": "addition", + "prompt": "add 5 and 3. Return only the number, no explanation.", + "result": [ + "8" + ], + "expected": "8", + "model": "qwen2.5:3b", + "router": "qwen2.5:3b", + "timestamp": "2026-03-19T15:42:19.097Z", + "passed": true, + "duration": 738, + "category": "ollama-basics" + }, + { + "test": "multiplication", + "prompt": "multiply 8 and 3. Return only the number, no explanation.", + "result": [ + "24" + ], + "expected": "24", + "model": "qwen2.5:3b", + "router": "qwen2.5:3b", + "timestamp": "2026-03-19T15:42:19.848Z", + "passed": true, + "duration": 745, + "category": "ollama-basics" + }, + { + "test": "division", + "prompt": "divide 15 by 3. Return only the number, no explanation.", + "result": [ + "5" + ], + "expected": "5", + "model": "qwen2.5:3b", + "router": "qwen2.5:3b", + "timestamp": "2026-03-19T15:42:20.529Z", + "passed": true, + "duration": 677, + "category": "ollama-basics" + } + ], + "highscores": [ + { + "test": "addition", + "rankings": [ + { + "model": "qwen2.5:3b", + "duration": 738, + "duration_secs": 0.738 + } + ] + }, + { + "test": "multiplication", + "rankings": [ + { + "model": "qwen2.5:3b", + "duration": 745, + "duration_secs": 0.745 + } + ] + }, + { + "test": "division", + "rankings": [ + { + "model": "qwen2.5:3b", + "duration": 677, + "duration_secs": 0.677 + } + ] + } + ], + "lastUpdated": "2026-03-19T15:42:20.529Z" +} \ No newline at end of file diff --git a/packages/kbot/tests/unit/reports/ollama-basics.md b/packages/kbot/tests/unit/reports/ollama-basics.md new file mode 100644 index 00000000..7df827d9 --- /dev/null +++ b/packages/kbot/tests/unit/reports/ollama-basics.md @@ -0,0 +1,50 @@ +# Ollama Basic Operations Test Results + +## Highscores + +### Performance Rankings (Duration) + +| Test | Model | Duration (ms) | Duration (s) | +|------|-------|--------------|--------------| +| addition | qwen2.5:3b | 738 | 0.74 | +| multiplication | qwen2.5:3b | 745 | 0.74 | +| division | qwen2.5:3b | 677 | 0.68 | + +## Summary + +- Total Tests: 3 +- Passed: 3 +- Failed: 0 +- Success Rate: 100.00% +- Average Duration: 720ms (0.72s) + +## Failed Tests + +*No failed tests* + +## Passed Tests + +### addition - qwen2.5:3b + +- Prompt: `add 5 and 3. Return only the number, no explanation.` +- Expected: `8` +- Actual: `8` +- Duration: 738ms (0.74s) +- Timestamp: 3/19/2026, 4:42:19 PM + +### multiplication - qwen2.5:3b + +- Prompt: `multiply 8 and 3. Return only the number, no explanation.` +- Expected: `24` +- Actual: `24` +- Duration: 745ms (0.74s) +- Timestamp: 3/19/2026, 4:42:19 PM + +### division - qwen2.5:3b + +- Prompt: `divide 15 by 3. Return only the number, no explanation.` +- Expected: `5` +- Actual: `5` +- Duration: 677ms (0.68s) +- Timestamp: 3/19/2026, 4:42:20 PM + diff --git a/packages/tm/package-lock.json b/packages/tm/package-lock.json new file mode 100644 index 00000000..bcd2d486 --- /dev/null +++ b/packages/tm/package-lock.json @@ -0,0 +1,1386 @@ +{ + "name": "tm", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "tm", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "@plastichub/kbot": "^1.1.23" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", + "license": "MIT", + "optional": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.28.5", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@plastichub/kbot": { + "version": "1.1.23", + "resolved": "https://registry.npmjs.org/@plastichub/kbot/-/kbot-1.1.23.tgz", + "integrity": "sha512-poMP/9HC55wxqIPB/kuezEb/S0SYb2uKFpw3z/7QypkxUouZ/V6n6N7qyLI4SvhehVC/fHoJ12vLYIKdh70wIA==", + "license": "ISC", + "dependencies": { + "node-emoji": "^2.2.0" + }, + "bin": { + "kbot": "main_node.js" + }, + "optionalDependencies": { + "puppeteer": "^23.11.1" + } + }, + "node_modules/@puppeteer/browsers": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.6.1.tgz", + "integrity": "sha512-aBSREisdsGH890S2rQqK82qmQYU3uFpSH8wcZWHgHzl3LfzsxAKbLNiAG9mO8v1Y0UICBeClICxPJvyr0rcuxg==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "debug": "^4.4.0", + "extract-zip": "^2.0.1", + "progress": "^2.0.3", + "proxy-agent": "^6.5.0", + "semver": "^7.6.3", + "tar-fs": "^3.0.6", + "unbzip2-stream": "^1.4.3", + "yargs": "^17.7.2" + }, + "bin": { + "browsers": "lib/cjs/main-cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@sindresorhus/is": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@tootallnate/quickjs-emscripten": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", + "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==", + "license": "MIT", + "optional": true + }, + "node_modules/@types/node": { + "version": "25.5.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.5.0.tgz", + "integrity": "sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==", + "license": "MIT", + "optional": true, + "dependencies": { + "undici-types": "~7.18.0" + } + }, + "node_modules/@types/yauzl": { + "version": "2.10.3", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", + "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", + "license": "MIT", + "optional": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 14" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "optional": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "license": "Python-2.0", + "optional": true + }, + "node_modules/ast-types": { + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", + "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/b4a": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.8.0.tgz", + "integrity": "sha512-qRuSmNSkGQaHwNbM7J78Wwy+ghLEYF1zNrSeMxj4Kgw6y33O3mXcQ6Ie9fRvfU/YnxWkOchPXbaLb73TkIsfdg==", + "license": "Apache-2.0", + "optional": true, + "peerDependencies": { + "react-native-b4a": "*" + }, + "peerDependenciesMeta": { + "react-native-b4a": { + "optional": true + } + } + }, + "node_modules/bare-events": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.8.2.tgz", + "integrity": "sha512-riJjyv1/mHLIPX4RwiK+oW9/4c3TEUeORHKefKAKnZ5kyslbN+HXowtbaVEqt4IMUB7OXlfixcs6gsFeo/jhiQ==", + "license": "Apache-2.0", + "optional": true, + "peerDependencies": { + "bare-abort-controller": "*" + }, + "peerDependenciesMeta": { + "bare-abort-controller": { + "optional": true + } + } + }, + "node_modules/bare-fs": { + "version": "4.5.6", + "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.5.6.tgz", + "integrity": "sha512-1QovqDrR80Pmt5HPAsMsXTCFcDYr+NSUKW6nd6WO5v0JBmnItc/irNRzm2KOQ5oZ69P37y+AMujNyNtG+1Rggw==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "bare-events": "^2.5.4", + "bare-path": "^3.0.0", + "bare-stream": "^2.6.4", + "bare-url": "^2.2.2", + "fast-fifo": "^1.3.2" + }, + "engines": { + "bare": ">=1.16.0" + }, + "peerDependencies": { + "bare-buffer": "*" + }, + "peerDependenciesMeta": { + "bare-buffer": { + "optional": true + } + } + }, + "node_modules/bare-os": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.8.0.tgz", + "integrity": "sha512-Dc9/SlwfxkXIGYhvMQNUtKaXCaGkZYGcd1vuNUUADVqzu4/vQfvnMkYYOUnt2VwQ2AqKr/8qAVFRtwETljgeFg==", + "license": "Apache-2.0", + "optional": true, + "engines": { + "bare": ">=1.14.0" + } + }, + "node_modules/bare-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-3.0.0.tgz", + "integrity": "sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "bare-os": "^3.0.1" + } + }, + "node_modules/bare-stream": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.10.0.tgz", + "integrity": "sha512-DOPZF/DDcDruKDA43cOw6e9Quq5daua7ygcAwJE/pKJsRWhgSSemi7qVNGE5kyDIxIeN1533G/zfbvWX7Wcb9w==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "streamx": "^2.25.0", + "teex": "^1.0.1" + }, + "peerDependencies": { + "bare-buffer": "*", + "bare-events": "*" + }, + "peerDependenciesMeta": { + "bare-buffer": { + "optional": true + }, + "bare-events": { + "optional": true + } + } + }, + "node_modules/bare-url": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.4.0.tgz", + "integrity": "sha512-NSTU5WN+fy/L0DDenfE8SXQna4voXuW0FHM7wH8i3/q9khUSchfPbPezO4zSFMnDGIf9YE+mt/RWhZgNRKRIXA==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "bare-path": "^3.0.0" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "optional": true + }, + "node_modules/basic-ftp": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.2.0.tgz", + "integrity": "sha512-VoMINM2rqJwJgfdHq6RiUudKt2BV+FY5ZFezP/ypmwayk68+NzzAQy4XXLlqsGD4MCzq3DrmNFD/uUmBJuGoXw==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "optional": true, + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": "*" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/chromium-bidi": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.11.0.tgz", + "integrity": "sha512-6CJWHkNRoyZyjV9Rwv2lYONZf1Xm0IuDyNq97nwSsxxP3wf5Bwy15K5rOvVKMtJ127jJBmxFUanSAOjgFRxgrA==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "mitt": "3.0.1", + "zod": "3.23.8" + }, + "peerDependencies": { + "devtools-protocol": "*" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "license": "ISC", + "optional": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT", + "optional": true + }, + "node_modules/cosmiconfig": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.1.tgz", + "integrity": "sha512-hr4ihw+DBqcvrsEDioRO31Z17x71pUYoNe/4h6Z0wB72p7MU7/9gH8Q3s12NFhHPfYBBOV3qyfUxmr/Yn3shnQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/data-uri-to-buffer": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz", + "integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 14" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "optional": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/degenerator": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz", + "integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "ast-types": "^0.13.4", + "escodegen": "^2.1.0", + "esprima": "^4.0.1" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/devtools-protocol": { + "version": "0.0.1367902", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1367902.tgz", + "integrity": "sha512-XxtPuC3PGakY6PD7dG66/o8KwJ/LkH2/EKe19Dcw58w53dv4/vSQEkn/SzuyhHE2q4zPgCkxQBxus3VV4ql+Pg==", + "license": "BSD-3-Clause", + "optional": true, + "peer": true + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT", + "optional": true + }, + "node_modules/emojilib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/emojilib/-/emojilib-2.4.0.tgz", + "integrity": "sha512-5U0rVMU5Y2n2+ykNLQqMoqklN9ICBT/KsvC1Gz6vqHbz2AXXGkG+Pm5rMWk/8Vjrr/mY9985Hi8DYzn1F09Nyw==", + "license": "MIT" + }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "license": "MIT", + "optional": true, + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escodegen": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "license": "BSD-2-Clause", + "optional": true, + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "license": "BSD-2-Clause", + "optional": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "license": "BSD-2-Clause", + "optional": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "license": "BSD-2-Clause", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/events-universal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/events-universal/-/events-universal-1.0.1.tgz", + "integrity": "sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "bare-events": "^2.7.0" + } + }, + "node_modules/extract-zip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", + "license": "BSD-2-Clause", + "optional": true, + "dependencies": { + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" + }, + "bin": { + "extract-zip": "cli.js" + }, + "engines": { + "node": ">= 10.17.0" + }, + "optionalDependencies": { + "@types/yauzl": "^2.9.1" + } + }, + "node_modules/fast-fifo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", + "license": "MIT", + "optional": true + }, + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "license": "MIT", + "optional": true, + "dependencies": { + "pend": "~1.2.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "license": "ISC", + "optional": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "license": "MIT", + "optional": true, + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-uri": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.5.tgz", + "integrity": "sha512-b1O07XYq8eRuVzBNgJLstU6FYc1tS6wnMtF1I1D9lE8LxZSOGZ7LhxN54yPP6mGw5f2CkXY2BQUL9Fx41qvcIg==", + "license": "MIT", + "optional": true, + "dependencies": { + "basic-ftp": "^5.0.2", + "data-uri-to-buffer": "^6.0.2", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "license": "MIT", + "optional": true, + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "license": "MIT", + "optional": true, + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause", + "optional": true + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ip-address": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.0.tgz", + "integrity": "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "license": "MIT", + "optional": true + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT", + "optional": true + }, + "node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "license": "MIT", + "optional": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "license": "MIT", + "optional": true + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "license": "MIT", + "optional": true + }, + "node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "license": "ISC", + "optional": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/mitt": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", + "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", + "license": "MIT", + "optional": true + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT", + "optional": true + }, + "node_modules/netmask": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", + "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/node-emoji": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-2.2.0.tgz", + "integrity": "sha512-Z3lTE9pLaJF47NyMhd4ww1yFTAP8YhYI8SleJiHzM46Fgpm5cnNzSl9XfzFNqbaz+VlJrIj3fXQ4DeN1Rjm6cw==", + "license": "MIT", + "dependencies": { + "@sindresorhus/is": "^4.6.0", + "char-regex": "^1.0.2", + "emojilib": "^2.4.0", + "skin-tone": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "optional": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/pac-proxy-agent": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.2.0.tgz", + "integrity": "sha512-TEB8ESquiLMc0lV8vcd5Ql/JAKAoyzHFXaStwjkzpOpC5Yv+pIzLfHvjTSdf3vpa2bMiUQrg9i6276yn8666aA==", + "license": "MIT", + "optional": true, + "dependencies": { + "@tootallnate/quickjs-emscripten": "^0.23.0", + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "get-uri": "^6.0.1", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.6", + "pac-resolver": "^7.0.1", + "socks-proxy-agent": "^8.0.5" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/pac-resolver": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz", + "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==", + "license": "MIT", + "optional": true, + "dependencies": { + "degenerator": "^5.0.0", + "netmask": "^2.0.2" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "license": "MIT", + "optional": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "license": "MIT", + "optional": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "license": "MIT", + "optional": true + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC", + "optional": true + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/proxy-agent": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.5.0.tgz", + "integrity": "sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A==", + "license": "MIT", + "optional": true, + "dependencies": { + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "http-proxy-agent": "^7.0.1", + "https-proxy-agent": "^7.0.6", + "lru-cache": "^7.14.1", + "pac-proxy-agent": "^7.1.0", + "proxy-from-env": "^1.1.0", + "socks-proxy-agent": "^8.0.5" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT", + "optional": true + }, + "node_modules/pump": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", + "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", + "license": "MIT", + "optional": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/puppeteer": { + "version": "23.11.1", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-23.11.1.tgz", + "integrity": "sha512-53uIX3KR5en8l7Vd8n5DUv90Ae9QDQsyIthaUFVzwV6yU750RjqRznEtNMBT20VthqAdemnJN+hxVdmMHKt7Zw==", + "deprecated": "< 24.15.0 is no longer supported", + "hasInstallScript": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@puppeteer/browsers": "2.6.1", + "chromium-bidi": "0.11.0", + "cosmiconfig": "^9.0.0", + "devtools-protocol": "0.0.1367902", + "puppeteer-core": "23.11.1", + "typed-query-selector": "^2.12.0" + }, + "bin": { + "puppeteer": "lib/cjs/puppeteer/node/cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/puppeteer-core": { + "version": "23.11.1", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-23.11.1.tgz", + "integrity": "sha512-3HZ2/7hdDKZvZQ7dhhITOUg4/wOrDRjyK2ZBllRB0ZCOi9u0cwq1ACHDjBB+nX+7+kltHjQvBRdeY7+W0T+7Gg==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@puppeteer/browsers": "2.6.1", + "chromium-bidi": "0.11.0", + "debug": "^4.4.0", + "devtools-protocol": "0.0.1367902", + "typed-query-selector": "^2.12.0", + "ws": "^8.18.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "license": "ISC", + "optional": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/skin-tone": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/skin-tone/-/skin-tone-2.0.0.tgz", + "integrity": "sha512-kUMbT1oBJCpgrnKoSr0o6wPtvRWT9W9UKvGLwfJYO2WuahZRHOpEyL1ckyMGgMWh0UdpmaoFqKKD29WTomNEGA==", + "license": "MIT", + "dependencies": { + "unicode-emoji-modifier-base": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks": { + "version": "2.8.7", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.7.tgz", + "integrity": "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==", + "license": "MIT", + "optional": true, + "dependencies": { + "ip-address": "^10.0.1", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz", + "integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==", + "license": "MIT", + "optional": true, + "dependencies": { + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "socks": "^2.8.3" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/streamx": { + "version": "2.25.0", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.25.0.tgz", + "integrity": "sha512-0nQuG6jf1w+wddNEEXCF4nTg3LtufWINB5eFEN+5TNZW7KWJp6x87+JFL43vaAUPyCfH1wID+mNVyW6OHtFamg==", + "license": "MIT", + "optional": true, + "dependencies": { + "events-universal": "^1.0.0", + "fast-fifo": "^1.3.2", + "text-decoder": "^1.1.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "optional": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "optional": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar-fs": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.1.2.tgz", + "integrity": "sha512-QGxxTxxyleAdyM3kpFs14ymbYmNFrfY+pHj7Z8FgtbZ7w2//VAgLMac7sT6nRpIHjppXO2AwwEOg0bPFVRcmXw==", + "license": "MIT", + "optional": true, + "dependencies": { + "pump": "^3.0.0", + "tar-stream": "^3.1.5" + }, + "optionalDependencies": { + "bare-fs": "^4.0.1", + "bare-path": "^3.0.0" + } + }, + "node_modules/tar-stream": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.8.tgz", + "integrity": "sha512-U6QpVRyCGHva435KoNWy9PRoi2IFYCgtEhq9nmrPPpbRacPs9IH4aJ3gbrFC8dPcXvdSZ4XXfXT5Fshbp2MtlQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "b4a": "^1.6.4", + "bare-fs": "^4.5.5", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" + } + }, + "node_modules/teex": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/teex/-/teex-1.0.1.tgz", + "integrity": "sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==", + "license": "MIT", + "optional": true, + "dependencies": { + "streamx": "^2.12.5" + } + }, + "node_modules/text-decoder": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.7.tgz", + "integrity": "sha512-vlLytXkeP4xvEq2otHeJfSQIRyWxo/oZGEbXrtEEF9Hnmrdly59sUbzZ/QgyWuLYHctCHxFF4tRQZNQ9k60ExQ==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "b4a": "^1.6.4" + } + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "license": "MIT", + "optional": true + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD", + "optional": true + }, + "node_modules/typed-query-selector": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/typed-query-selector/-/typed-query-selector-2.12.1.tgz", + "integrity": "sha512-uzR+FzI8qrUEIu96oaeBJmd9E7CFEiQ3goA5qCVgc4s5llSubcfGHq9yUstZx/k4s9dXHVKsE35YWoFyvEqEHA==", + "license": "MIT", + "optional": true + }, + "node_modules/unbzip2-stream": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", + "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", + "license": "MIT", + "optional": true, + "dependencies": { + "buffer": "^5.2.1", + "through": "^2.3.8" + } + }, + "node_modules/undici-types": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", + "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", + "license": "MIT", + "optional": true + }, + "node_modules/unicode-emoji-modifier-base": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unicode-emoji-modifier-base/-/unicode-emoji-modifier-base-1.0.0.tgz", + "integrity": "sha512-yLSH4py7oFH3oG/9K+XWrz1pSi3dfUrWEnInbxMfArOfc1+33BlGPQtLsOYwvdMy11AwUBetYuaRxSPqgkq+8g==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "optional": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC", + "optional": true + }, + "node_modules/ws": { + "version": "8.19.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz", + "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "license": "ISC", + "optional": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "license": "MIT", + "optional": true, + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "license": "ISC", + "optional": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "license": "MIT", + "optional": true, + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, + "node_modules/zod": { + "version": "3.23.8", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz", + "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==", + "license": "MIT", + "optional": true, + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + } + } +} diff --git a/packages/tm/package.json b/packages/tm/package.json new file mode 100644 index 00000000..37e302bf --- /dev/null +++ b/packages/tm/package.json @@ -0,0 +1,16 @@ +{ + "name": "tm", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "type": "commonjs", + "dependencies": { + "@plastichub/kbot": "^1.1.23" + } +}