UNPKG

@plastichub/osr-ai-tools

Version:

CLI and library for LLM tools

187 lines 50.3 kB
{ "model": "anthropic/claude-3.5-sonnet", "messages": [ { "role": "system", "content": "You are a helpful assistant that modifies existing project files based on user requirements." }, { "role": "system", "content": "for Typescript boilerplates, use this layout for CLI projects: \nsrc/index.ts (create ts logger)\nsrc/main.ts (yargs main entry)\nsrc/constants.ts (tslog logger name)\nsrc/zod_schemas.ts (all zod schemas go here)\nsrc/commands/index.ts (register all commands from src/commands/** here, commands always import functions from src/lib/category )\nsrc/commands/types.ts (command to write zod schemas to Typescript interfaces)\npackage.json (leave dependencies empty, add common scripts)" }, { "role": "system", "content": "when using yargs, all commands are async" }, { "role": "user", "content": "for Typescript, dont use chalk, commander, ora, or any other fancy library, just use the basics, always use imports, never require. use tslog, yargs, axios and Zod whenevern possible" }, { "role": "user", "content": "## Filesystem \r\n\r\nFor filesystem operations, use\r\n\r\nimport { sync as rm } from '@plastichub/fs/remove' (path)\r\nimport { sync as dir } from '@plastichub/fs/dir' (path)\r\nimport { sync as write } from '@plastichub/fs/write' (path, content)\r\nimport { sync as read } from '@plastichub/fs/read' (path)\r\nimport { filesEx as glob } from '@plastichub/osr-commons/_glob' (directory,glob | glob[])\r\n\r\n## Configuration\r\n\r\nAPI keys and other settings:\r\n\r\n```ts\r\nimport { CONFIG_DEFAULT } from '@plastichub/osr-commons'\r\nexport const foo = (yarg) => {\r\n const config = CONFIG_DEFAULT(args.env_key) as any\r\n if (!config) {\r\n logger.warn('No config found!')\r\n return\r\n }\r\n if (config && !config.openai.key) {\r\n logger.warn('No OpenAI key found in config!')\r\n return\r\n }\r\n const api_key = argv.openai_key || process.env.OPENAI_API_KEY || config.openai.key\r\n}\r\n```\r\n\r\n## Zod Schemas\r\n\r\nThe framework provides tools to convert from a Zod schema to Yargs as follows\r\n\r\n```ts\r\n\r\nimport { toYargs } from '@plastichub/osr-commons'\r\nimport { MySchema } from 'src/schemas.ts'\r\n// example : const options = (yargs: CLI.Argv) => toYargs(yargs, MySchema())\r\n```\r\n\r\nAdditionally, all Zod schemas will be exported on demand, via Yargs command \"types\"\r\n\r\n```ts\r\nimport { generate_interfaces } from '@plastichub/osr-commons'\r\nimport { MySchema } from 'src/schemas'\r\n\r\nexport const types = () => generate_interfaces(\r\n [\r\n MySchema()\r\n ], 'src/zod_types.ts')\r\n```\r\n\r\n### Logging\r\n\r\nEach package has a tslog factory at src/index.ts. Use it for all commands and library functions\r\n\r\n```ts\r\nexport { Logger } from 'tslog'\r\nimport { createLogger } from '@plastichub/osr-log'\r\nimport { Logger } from 'tslog'\r\nexport const logger:Logger<unknown> = createLogger('Package Name')\r\n```\r\n\r\n### LLM Tools\r\n\r\nLLM Tools are specified as follows\r\n\r\n- always export \"tools\" as the main function\r\n- dont register LLM tools as yarg commands\r\n- seperate the tool's implementation in src/lib/tools\r\n- LLM tools require 'openai' as dependency\r\n\r\neg: src/tools/fs:\r\n\r\n```ts\r\nimport { join } from 'path'\r\nimport * as path from 'path'\r\nimport { RunnableToolFunction } from 'openai/lib/RunnableFunction'\r\nimport { isString } from '@plastichub/core/primitives'\r\nimport { sync as dir } from '@plastichub/fs/dir'\r\nimport { sync as write } from '@plastichub/fs/write'\r\nimport { resolve } from \"@plastichub/osr-commons\"\r\nimport { logger } from '../'\r\n\r\nexport const tools = (target:any, variables:Record<string,string>={}): Array<any> => {\r\n return [\r\n {\r\n type: 'function',\r\n function: {\r\n name: \"read_file\",\r\n description: \"read a file, at given a path\",\r\n parameters: {\r\n type: \"object\",\r\n properties: {\r\n file: {\r\n type: \"object\",\r\n properties: {\r\n path: { type: \"string\" }\r\n }\r\n }\r\n },\r\n required: [\"file\"],\r\n },\r\n function: async (ret) => {\r\n try {\r\n const { file } = ret as any\r\n const filePath = path.resolve(resolve(join(target, file.path),false,variables))\r\n logger.debug(`Tool::ReadFile Reading file ${filePath}`)\r\n } catch (error) {\r\n logger.error(`Error reading file`, error)\r\n } \r\n },\r\n parse: JSON.parse\r\n }\r\n } as RunnableToolFunction<{ id: string }>\r\n ]\r\n}\r\n```\r\n### Typescript tsconfig\r\n\r\nUse this defaults\r\n\r\n```json\r\n\"compilerOptions\": {\r\n \"target\": \"ES2020\",\r\n \"module\": \"commonjs\",\r\n \"outDir\": \"./dist\",\r\n \"rootDir\": \"./src\",\r\n \"strict\": true,\r\n \"esModuleInterop\": true,\r\n \"skipLibCheck\": true,\r\n \"allowJs\": true,\r\n \"noImplicitAny\": false,\r\n \"strictNullChecks\": false,\r\n \"forceConsistentCasingInFileNames\": true\r\n },\r\n```\r\n\r\n### Yargs\r\n\r\nCommands are registered as follows (src/command/index.ts) :\r\n\r\n```ts\r\nimport type { Argv } from 'yargs'\r\nimport { types } from './types'\r\nexport const commands = (yargs: Argv) => \r\n{\r\n return yargs\r\n .command('types', 'Generate TypeScript interfaces from Zod schemas', {}, types)\r\n .strict()\r\n .help()\r\n}\r\n```\r\n\r\n### Nodejs\r\n\r\n- import built-ins always as import * as 'path'\r\n" }, { "role": "user", "content": "Modify the following project files : Update package.json for tools (scripts)\n\nCurrent files:\n[\n {\n \"path\": \"package.json\",\n \"content\": \"{\\n \\\"name\\\": \\\"llm-tools-cli\\\",\\n \\\"version\\\": \\\"1.0.0\\\",\\n \\\"description\\\": \\\"CLI and library for LLM tools\\\",\\n \\\"main\\\": \\\"dist/index.js\\\",\\n \\\"bin\\\": {\\n \\\"llm-tools\\\": \\\"./dist/main.js\\\"\\n },\\n \\\"scripts\\\": {\\n \\\"build\\\": \\\"tsc\\\",\\n \\\"start\\\": \\\"node dist/main.js\\\",\\n \\\"dev\\\": \\\"ts-node src/main.ts\\\",\\n \\\"types\\\": \\\"ts-node src/main.ts types\\\",\\n \\\"list\\\": \\\"ts-node src/main.ts list\\\"\\n },\\n \\\"dependencies\\\": {\\n \\\"@plastichub/core\\\": \\\"^0.2.6\\\",\\n \\\"@plastichub/fs\\\": \\\"^0.13.39\\\",\\n \\\"@plastichub/osr-commons\\\": \\\"^0.3.7\\\",\\n \\\"@plastichub/osr-log\\\": \\\"^0.1.1\\\",\\n \\\"axios\\\": \\\"^1.7.9\\\",\\n \\\"openai\\\": \\\"^4.76.3\\\",\\n \\\"simple-git\\\": \\\"^3.22.0\\\",\\n \\\"tslog\\\": \\\"^4.9.3\\\",\\n \\\"yargs\\\": \\\"^17.7.2\\\",\\n \\\"zod\\\": \\\"^3.24.1\\\"\\n },\\n \\\"devDependencies\\\": {\\n \\\"@types/node\\\": \\\"^18.0.0\\\",\\n \\\"@types/yargs\\\": \\\"^17.0.0\\\",\\n \\\"ts-node\\\": \\\"^10.9.0\\\",\\n \\\"typescript\\\": \\\"^4.9.0\\\"\\n }\\n}\"\n },\n {\n \"path\": \"Readme.md\",\n \"content\": \"# LLM Tools CLI\\n\\nCommand-line interface and library for LLM tools providing filesystem, npm, git, and terminal operations.\\n\\n## Setup\\n\\n1. Install dependencies:\\n```bash\\nnpm install\\n```\\n\\n2. Build the project:\\n```bash\\nnpm run build\\n```\\n\\n3. Configure environment:\\nEither set environment variable:\\n```bash\\nexport OPENAI_API_KEY=your-key-here\\n```\\nOr create a configuration file (e.g. `.env.dev.json`):\\n```json\\n{\\n \\\"openai\\\": {\\n \\\"key\\\": \\\"your-key-here\\\"\\n }\\n}\\n```\\nThen use with --env_key parameter:\\n```bash\\nnpm start invoke --env_key dev\\n```\\n\\n## Available Commands\\n\\n### Generate TypeScript Types\\nGenerates TypeScript interfaces from Zod schemas:\\n```bash\\nnpm run types\\n```\\n\\n### File Operations\\n```bash\\n# List files in directory\\nnpm start fs list --directory ./src --pattern \\\"**/*.ts\\\"\\n\\n# Remove files\\nnpm start fs remove --path ./temp.txt\\n\\n# Read file content\\nnpm start fs read --path ./src/config.json\\n\\n# Write file\\nnpm start fs write --path ./output.txt --content \\\"Hello World\\\"\\n```\\n\\n### Git Operations\\n```bash\\n# Commit files\\nnpm start git commit --files src/index.ts src/main.ts --message \\\"Updated core files\\\"\\n\\n# Revert files\\nnpm start git revert --files src/config.ts\\n\\n# Switch branch\\nnpm start git switch --branch main --remote origin\\n\\n# Get raw file from GitHub\\nnpm start git raw --url \\\"https://raw.githubusercontent.com/user/repo/main/file.txt\\\"\\n# or\\nnpm start git raw --repo \\\"user/repo\\\" --path \\\"path/to/file.txt\\\"\\n```\\n\\n### NPM Commands\\n```bash\\n# Install dependencies\\nnpm start npm run --command install --args \\\"-D\\\" \\\"typescript\\\"\\n\\n# Run scripts\\nnpm start npm run --command test\\n```\\n\\n### Terminal Commands\\n```bash\\n# Basic command\\nnpm start terminal exec --command \\\"echo\\\" --args \\\"hello\\\"\\n\\n# With working directory\\nnpm start terminal exec --command \\\"ls\\\" --cwd \\\"./src\\\"\\n\\n# Background process\\nnpm start terminal exec --command \\\"serve\\\" --background true\\n\\n# New window\\nnpm start terminal exec --command \\\"vim\\\" --window true\\n```\\n\\n## Library Usage\\n\\n### Core Imports\\nAlways use ES imports:\\n```typescript\\nimport * as path from 'path'\\nimport * as fs from 'fs'\\n```\\n\\n### Logger Setup\\n```typescript\\nimport { Logger } from 'tslog'\\nimport { createLogger } from '@plastichub/osr-log'\\n\\nexport const logger: Logger<unknown> = createLogger('package-name')\\n```\\n\\n### Configuration Access\\n```typescript\\nimport { CONFIG_DEFAULT } from '@plastichub/osr-commons'\\n\\nconst config = CONFIG_DEFAULT('env_key')\\nif (!config) {\\n logger.warn('No config found!')\\n return\\n}\\nif (!config.openai?.key) {\\n logger.warn('No OpenAI key found in config!')\\n return\\n}\\nconst api_key = process.env.OPENAI_API_KEY || config.openai.key\\n```\\n\\n### File Operations\\n```typescript\\nimport { sync as rm } from '@plastichub/fs/remove'\\nimport { sync as dir } from '@plastichub/fs/dir'\\nimport { sync as write } from '@plastichub/fs/write'\\nimport { sync as read } from '@plastichub/fs/read'\\nimport { filesEx as glob } from '@plastichub/osr-commons/_glob'\\n\\n// Create/ensure directory\\nawait dir('path/to/dir')\\n\\n// Write file\\nawait write('file.txt', 'content')\\n\\n// Read file\\nconst content = await read('file.txt')\\n\\n// Remove file\\nawait rm('file.txt')\\n\\n// Get files by glob pattern\\nconst files = await glob('src', ['**/*.ts'])\\n```\\n\\n### Using Zod Schemas\\n```typescript\\nimport { toYargs } from '@plastichub/osr-commons'\\nimport { FileListingOptionsSchema } from './zod_schemas'\\n\\n// Convert Zod schema to Yargs options\\nconst options = (yargs: CLI.Argv) => toYargs(yargs, FileListingOptionsSchema)\\n```\\n\\n### Generate TypeScript Interfaces\\n```typescript\\nimport { generate_interfaces } from '@plastichub/osr-commons'\\nimport { FileListingOptionsSchema } from './zod_schemas'\\n\\nexport const types = () => generate_interfaces(\\n [FileListingOptionsSchema],\\n 'src/zod_types.ts'\\n)\\n```\\n\\n### Create LLM Tools\\n```typescript\\nimport { RunnableToolFunction } from 'openai/lib/RunnableFunction'\\nimport { logger } from '../'\\n\\nexport const tools = (target: any, variables: Record<string,string> = {}): Array<any> => [\\n {\\n type: 'function',\\n function: {\\n name: \\\"read_file\\\",\\n description: \\\"Read file content\\\",\\n parameters: {\\n type: \\\"object\\\",\\n properties: {\\n path: { type: \\\"string\\\" }\\n },\\n required: [\\\"path\\\"],\\n },\\n function: async ({ path }) => {\\n try {\\n const content = await read(path)\\n return content\\n } catch (error) {\\n logger.error(`Error reading file`, error)\\n throw error\\n } \\n },\\n parse: JSON.parse\\n }\\n } as RunnableToolFunction<{ id: string }>\\n]\\n```\\n\\n## Project Structure\\n```\\nsrc/\\n ├── commands/ # Command implementations\\n │ ├── index.ts # Command registry\\n │ └── types.ts # Types command\\n ├── lib/ # Core functionality\\n │ └── tools/ # Tool implementations\\n ├── constants.ts # Logger name constant\\n ├── index.ts # Logger setup\\n ├── main.ts # CLI entry point\\n ├── zod_schemas.ts # Zod schemas\\n └── zod_types.ts # Generated TypeScript interfaces\\n```\\n\\n## Notes\\n\\n- All commands are asynchronous when using yargs\\n- Use tslog for consistent logging across the application\\n- Always use Zod schemas for command parameters\\n- Use axios for HTTP requests\\n- Configuration can be provided via environment variables or config files\\n- TypeScript interfaces can be generated from Zod schemas using the `types` command\\n\"\n },\n {\n \"path\": \"src\\\\zod_types.ts\",\n \"content\": \"export interface IFileListingOptions {\\n /** Directory path to list files from */\\n directory: string;\\n /** Glob pattern for filtering files */\\n pattern?: string | undefined;\\n}\\nexport interface IFileRemovalOptions {\\n /** Path of the file to remove */\\n path: string;\\n}\\nexport interface IGitCommitOptions {\\n /** Files to commit */\\n files: string[];\\n /** Commit message */\\n message: string;\\n}\\nexport interface IGitRevertOptions {\\n /** Files to revert */\\n files: string[];\\n}\\nexport interface IGitSwitchVersionOptions {\\n /** Branch name to switch to */\\n branch: string;\\n /** Remote name */\\n remote?: string;\\n}\\nexport interface IInvokeToolOptions {\\n /** Tool category to use (fs, npm, git, terminal) */\\n tools: string;\\n /** Function name to invoke */\\n function: string;\\n /** Target directory */\\n target?: string;\\n /** JSON string of parameters */\\n params?: string | undefined;\\n /** Path to write the output to */\\n output?: string | undefined;\\n /** Environment configuration key */\\n env_key?: string | undefined;\\n}\\nexport interface IToolListingOptions {\\n /** Path to write the output to */\\n output?: string;\\n}\\nexport interface ITerminalCommandOptions {\\n /** Command to execute */\\n command: string;\\n /** Command arguments */\\n args?: string[] | undefined;\\n /** Working directory for command execution */\\n cwd?: string | undefined;\\n /** Run command in background (non-blocking) */\\n background?: boolean | undefined;\\n /** Open command in new terminal window */\\n window?: boolean | undefined;\\n /** Run process detached from parent */\\n detached?: boolean | undefined;\\n}\"\n },\n {\n \"path\": \"src\\\\zod_schemas.ts\",\n \"content\": \"import { z } from 'zod';\\n\\n/** Schema for listing files in a directory */\\nexport const FileListingOptionsSchema = z.object({\\n directory: z.string().describe('Directory path to list files from'),\\n pattern: z.string().optional().describe('Glob pattern for filtering files')\\n}).describe('IFileListingOptions')\\n\\n/** Schema for file removal operations */\\nexport const FileRemovalOptionsSchema = z.object({\\n path: z.string().describe('Path of the file to remove')\\n}).describe('IFileRemovalOptions');\\n\\n/** Schema for git commit operations */\\nexport const GitCommitSchema = z.object({\\n files: z.array(z.string()).describe('Files to commit'),\\n message: z.string().describe('Commit message')\\n}).describe('IGitCommitOptions');\\n\\n/** Schema for git revert operations */\\nexport const GitRevertSchema = z.object({\\n files: z.array(z.string()).describe('Files to revert')\\n}).describe('IGitRevertOptions');\\n\\n/** Schema for git version switch operations */\\nexport const GitSwitchVersionSchema = z.object({\\n branch: z.string().describe('Branch name to switch to'),\\n remote: z.string().default('origin').describe('Remote name')\\n}).describe('IGitSwitchVersionOptions');\\n\\n/** Schema for git raw file retrieval */\\nexport const GitRawFileSchema = z.object({\\n url: z.string().optional().describe('Full GitHub raw URL'),\\n repo: z.string().optional().describe('Repository in format owner/repo'),\\n path: z.string().optional().describe('File path within repository')\\n}).refine(\\n data => (data.url) || (data.repo && data.path),\\n 'Either url or both repo and path must be provided'\\n).describe('IGitRawFileOptions');\\n\\n/** Schema for npm run command */\\nexport const NpmRunSchema = z.object({\\n command: z.string().describe('Command to run (e.g. install, test, etc)'),\\n args: z.array(z.string()).optional().describe('Additional arguments for the command')\\n}).describe('INpmRunOptions');\\n\\n/** Schema for terminal command execution */\\nexport const TerminalCommandSchema = z.object({\\n command: z.string().describe('Command to execute'),\\n args: z.array(z.string()).optional().describe('Command arguments'),\\n cwd: z.string().optional().describe('Working directory for command execution'),\\n background: z.boolean().optional().describe('Run command in background (non-blocking)'),\\n window: z.boolean().optional().describe('Open command in new terminal window'),\\n detached: z.boolean().optional().describe('Run process detached from parent')\\n}).describe('ITerminalCommandOptions');\\n\\n/** Schema for tool invocation parameters */\\nexport const InvokeToolSchema = z.object({\\n tools: z.string().describe('Tool category to use (fs, npm, git, terminal)'),\\n function: z.string().describe('Function name to invoke'),\\n target: z.string().default(process.cwd()).describe('Target directory'),\\n params: z.string().optional().describe('JSON string of parameters'),\\n output: z.string().optional().describe('Path to write the output to'),\\n env_key: z.string().optional().describe('Environment configuration key')\\n}).describe('IInvokeToolOptions');\\n\\n/** Schema for list command options */\\nexport const ListCommandSchema = z.object({\\n output: z.string().default(\\\"./llm-tools.json\\\").describe('Output file path for tools list')\\n}).describe('IListCommandOptions');\\n\\n/** Schema for tool listing options */\\nexport const ToolListingOptionsSchema = z.object({\\n output: z.string().default('./llm-tools.json').describe('Path to write the output to')\\n}).describe('IToolListingOptions');\"\n },\n {\n \"path\": \"src\\\\tools.ts\",\n \"content\": \"import { tools as fsTools } from './lib/tools/fs';\\nimport { tools as npmTools } from './lib/tools/npm';\\nimport { tools as gitTools } from './lib/tools/git';\\nimport { tools as terminalTools } from './lib/tools/terminal';\\n\\nexport const tools = {\\n fs: fsTools,\\n npm: npmTools,\\n git: gitTools,\\n terminal: terminalTools\\n};\"\n },\n {\n \"path\": \"src\\\\main.ts\",\n \"content\": \"#!/usr/bin/env node\\nimport yargs from 'yargs';\\nimport { commands } from './commands';\\nimport { logger } from './';\\n\\nasync function main() {\\n try {\\n const argv = await commands(yargs).argv;\\n } catch (error) {\\n logger.error('Error executing command:', error);\\n process.exit(1);\\n }\\n}\\n\\nmain();\"\n },\n {\n \"path\": \"src\\\\index.ts\",\n \"content\": \"import { Logger } from 'tslog';\\nimport { createLogger } from '@plastichub/osr-log';\\nexport const logger: Logger<unknown> = createLogger('llm-tools-cli');\\n\"\n },\n {\n \"path\": \"src\\\\constants.ts\",\n \"content\": \"export const LOGGER_NAME = 'llm-tools-cli';\\n\"\n },\n {\n \"path\": \"src\\\\lib\\\\tools\\\\terminal.ts\",\n \"content\": \"import * as path from 'path';\\nimport { RunnableToolFunction } from 'openai/lib/RunnableFunction';\\nimport { exec, spawn } from 'child_process';\\nimport { promisify } from 'util';\\nimport { logger } from '../../index';\\n\\nconst execAsync = promisify(exec);\\n\\nexport const tools = (target: string): Array<any> => {\\n return [\\n {\\n type: 'function',\\n function: {\\n name: 'execute_command',\\n description: 'Execute a terminal command and capture output',\\n parameters: {\\n type: 'object',\\n properties: {\\n command: { \\n type: 'string',\\n description: 'Command to execute'\\n },\\n args: {\\n type: 'array',\\n items: { type: 'string' },\\n description: 'Command arguments',\\n optional: true\\n },\\n cwd: {\\n type: 'string',\\n description: 'Working directory for command execution',\\n optional: true\\n },\\n background: {\\n type: 'boolean',\\n description: 'Run command in background (non-blocking)',\\n optional: true\\n },\\n window: {\\n type: 'boolean',\\n description: 'Open command in new terminal window',\\n optional: true\\n },\\n detached: {\\n type: 'boolean',\\n description: 'Run process detached from parent',\\n optional: true\\n }\\n },\\n required: ['command']\\n },\\n function: async (params: any) => {\\n try {\\n const workingDir = params.cwd ? path.join(target, params.cwd) : target;\\n const args = params.args || [];\\n \\n // Handle window mode (platform specific)\\n if (params.window) {\\n const isWindows = process.platform === 'win32';\\n if (isWindows) {\\n spawn('cmd', ['/c', 'start', 'cmd', '/k', params.command, ...args], {\\n cwd: workingDir,\\n detached: true,\\n stdio: 'ignore'\\n });\\n } else {\\n // For macOS/Linux\\n spawn('x-terminal-emulator', ['-e', `${params.command} ${args.join(' ')}`], {\\n cwd: workingDir,\\n detached: true,\\n stdio: 'ignore'\\n });\\n }\\n return {\\n success: true,\\n output: 'Command launched in new window',\\n error: null\\n };\\n }\\n\\n // Handle background/detached mode\\n if (params.background || params.detached) {\\n const child = spawn(params.command, args, {\\n cwd: workingDir,\\n detached: params.detached === true,\\n stdio: 'ignore'\\n });\\n\\n if (params.detached) {\\n child.unref();\\n }\\n\\n return {\\n success: true,\\n output: `Process started with PID: ${child.pid}`,\\n error: null\\n };\\n }\\n\\n // Regular synchronous execution\\n const fullCommand = `${params.command} ${args.join(' ')}`.trim();\\n logger.debug(`Tool::ExecuteCommand Running '${fullCommand}' in ${workingDir}`);\\n const { stdout, stderr } = await execAsync(fullCommand, {\\n cwd: workingDir\\n });\\n\\n return {\\n success: !stderr,\\n output: stdout,\\n error: stderr || null\\n };\\n } catch (error: any) {\\n logger.error('Error executing command', error);\\n return {\\n success: false,\\n output: null,\\n error: error.message\\n };\\n }\\n },\\n parse: JSON.parse\\n }\\n } as RunnableToolFunction<any>\\n ];\\n};\"\n },\n {\n \"path\": \"src\\\\lib\\\\tools\\\\npm.ts\",\n \"content\": \"import * as path from 'path';\\nimport { RunnableToolFunction } from 'openai/lib/RunnableFunction';\\nimport { exec } from 'child_process';\\nimport { promisify } from 'util';\\nimport { logger } from '../../index';\\n\\nconst execAsync = promisify(exec);\\n\\nexport const tools = (target: string): Array<any> => {\\n return [\\n {\\n type: 'function',\\n function: {\\n name: 'build_project',\\n description: 'Build project using pnpm build command',\\n parameters: {\\n type: 'object',\\n properties: {},\\n required: []\\n },\\n function: async () => {\\n try {\\n logger.debug(`Tool::BuildProject Building project at ${target}`);\\n const { stdout, stderr } = await execAsync('pnpm build', {\\n cwd: target\\n });\\n return {\\n success: !stderr,\\n output: stdout,\\n error: stderr || null\\n };\\n } catch (error : any) {\\n logger.error('Error building project', error);\\n return {\\n success: false,\\n output: null,\\n error: error.message\\n };\\n }\\n },\\n parse: JSON.parse\\n }\\n } as RunnableToolFunction<any>,\\n {\\n type: 'function',\\n function: {\\n name: 'run_npm',\\n description: 'Run an npm/pnpm command',\\n parameters: {\\n type: 'object',\\n properties: {\\n command: { type: 'string', description: 'Command to run (e.g. install, test, etc)' },\\n args: { \\n type: 'array',\\n items: { type: 'string' },\\n description: 'Additional arguments for the command',\\n optional: true\\n }\\n },\\n required: ['command']\\n },\\n function: async (params: any) => {\\n try {\\n const args = params.args ? params.args.join(' ') : '';\\n const fullCommand = `pnpm ${params.command} ${args}`.trim();\\n logger.debug(`Tool::RunNpm Running command: ${fullCommand}`);\\n const { stdout, stderr } = await execAsync(fullCommand, {\\n cwd: target\\n });\\n\\n return {\\n success: !stderr,\\n output: stdout,\\n error: stderr || null\\n };\\n } catch (error: any) {\\n logger.error('Error running npm command', error);\\n return {\\n success: false,\\n output: null,\\n error: error.message\\n };\\n }\\n },\\n parse: JSON.parse\\n }\\n } as RunnableToolFunction<any>\\n ];\\n};\"\n },\n {\n \"path\": \"src\\\\lib\\\\tools\\\\git.ts\",\n \"content\": \"import * as path from 'path';\\nimport { RunnableToolFunction } from 'openai/lib/RunnableFunction';\\nimport simpleGit, { SimpleGit } from 'simple-git';\\nimport axios from 'axios';\\nimport { logger } from '../../index';\\n\\nexport const tools = (target: string): Array<any> => {\\n const git: SimpleGit = simpleGit(target);\\n\\n return [\\n {\\n type: 'function',\\n function: {\\n name: 'commit_files',\\n description: 'Commit files to git repository',\\n parameters: {\\n type: 'object',\\n properties: {\\n files: {\\n type: 'array',\\n items: { type: 'string' }\\n },\\n message: { type: 'string' }\\n },\\n required: ['files', 'message']\\n },\\n function: async (params: any) => {\\n try {\\n logger.debug(`Tool::Git Committing files with message: ${params.message}`);\\n await git.add(params.files);\\n const result = await git.commit(params.message);\\n return {\\n success: true,\\n output: result,\\n error: null\\n };\\n } catch (error: any) {\\n logger.error('Error committing files', error);\\n return {\\n success: false,\\n output: null,\\n error: error.message\\n };\\n }\\n },\\n parse: JSON.parse\\n }\\n } as RunnableToolFunction<any>,\\n {\\n type: 'function',\\n function: {\\n name: 'revert_files',\\n description: 'Revert specified files in git repository',\\n parameters: {\\n type: 'object',\\n properties: {\\n files: {\\n type: 'array',\\n items: { type: 'string' }\\n }\\n },\\n required: ['files']\\n },\\n function: async (params: any) => {\\n try {\\n logger.debug(`Tool::Git Reverting files: ${params.files.join(', ')}`);\\n await git.checkout(['--', ...params.files]);\\n return {\\n success: true,\\n output: 'Files reverted successfully',\\n error: null\\n };\\n } catch (error: any) {\\n logger.error('Error reverting files', error);\\n return {\\n success: false,\\n output: null,\\n error: error.message\\n };\\n }\\n },\\n parse: JSON.parse\\n }\\n } as RunnableToolFunction<any>,\\n {\\n type: 'function',\\n function: {\\n name: 'switch_version',\\n description: 'Switch to previous version from remote',\\n parameters: {\\n type: 'object',\\n properties: {\\n branch: { type: 'string' },\\n remote: { \\n type: 'string',\\n default: 'origin'\\n }\\n },\\n required: ['branch']\\n },\\n function: async (params: any) => {\\n try {\\n const remote = params.remote || 'origin';\\n logger.debug(`Tool::Git Switching to branch ${params.branch} from ${remote}`);\\n const result = await git.checkout(`${remote}/${params.branch}`);\\n return {\\n success: true,\\n output: result,\\n error: null\\n };\\n } catch (error: any) {\\n logger.error('Error switching version', error);\\n return {\\n success: false,\\n output: null,\\n error: error.message\\n };\\n }\\n },\\n parse: JSON.parse\\n }\\n } as RunnableToolFunction<any>,\\n {\\n type: 'function',\\n function: {\\n name: 'get_raw_file',\\n description: 'Retrieve raw content of a file from GitHub repository',\\n parameters: {\\n type: 'object',\\n properties: {\\n url: { \\n type: 'string',\\n description: 'Full GitHub raw URL or repository path'\\n },\\n repo: {\\n type: 'string',\\n description: 'Repository in format owner/repo'\\n },\\n path: {\\n type: 'string',\\n description: 'File path within repository'\\n }\\n },\\n oneOf: [\\n { required: ['url'] },\\n { required: ['repo', 'path'] }\\n ]\\n },\\n function: async (params: any) => {\\n try {\\n let fileUrl = params.url;\\n if (!fileUrl && params.repo && params.path) {\\n fileUrl = `https://raw.githubusercontent.com/${params.repo}/main/${params.path}`;\\n }\\n \\n logger.debug(`Tool::Git Fetching raw file from ${fileUrl}`);\\n const response = await axios.get(fileUrl);\\n return {\\n success: true,\\n content: response.data,\\n error: null\\n };\\n } catch (error: any) {\\n logger.error('Error fetching raw file', error);\\n return {\\n success: false,\\n content: null,\\n error: error.message\\n };\\n }\\n },\\n parse: JSON.parse\\n }\\n } as RunnableToolFunction<any>\\n ];\\n};\"\n },\n {\n \"path\": \"src\\\\lib\\\\tools\\\\fs.ts\",\n \"content\": \"import * as path from 'path';\\nimport { RunnableToolFunction } from 'openai/lib/RunnableFunction';\\nimport { sync as dir } from '@plastichub/fs/dir';\\nimport { sync as rm } from '@plastichub/fs/remove';\\nimport { filesEx as glob } from '@plastichub/osr-commons/_glob';\\nimport { logger } from '../../index';\\n\\nexport const tools = (target: string): Array<any> => {\\n return [\\n {\\n type: 'function',\\n function: {\\n name: 'list_files',\\n description: 'List all files in a directory',\\n parameters: {\\n type: 'object',\\n properties: {\\n directory: { type: 'string' },\\n pattern: { type: 'string', optional: true }\\n },\\n required: ['directory']\\n },\\n function: async (params: any) => {\\n try {\\n const directory = path.join(target, params.directory);\\n const pattern = params.pattern || '**/*';\\n logger.debug(`Tool::ListFiles Listing files in ${directory} with pattern ${pattern}`);\\n return glob(directory, [pattern]);\\n } catch (error) {\\n logger.error('Error listing files', error);\\n throw error;\\n }\\n },\\n parse: JSON.parse\\n }\\n } as RunnableToolFunction<any>,\\n {\\n type: 'function',\\n function: {\\n name: 'remove_file',\\n description: 'Remove a file at given path',\\n parameters: {\\n type: 'object',\\n properties: {\\n path: { type: 'string' }\\n },\\n required: ['path']\\n },\\n function: async (params: any) => {\\n try {\\n const filePath = path.join(target, params.path);\\n logger.debug(`Tool::RemoveFile Removing file ${filePath}`);\\n rm(filePath);\\n return true;\\n } catch (error) {\\n logger.error('Error removing file', error);\\n throw error;\\n }\\n },\\n parse: JSON.parse\\n }\\n } as RunnableToolFunction<any>\\n ];\\n};\\n\"\n },\n {\n \"path\": \"src\\\\commands\\\\types.ts\",\n \"content\": \"import { generate_interfaces } from '@plastichub/osr-commons';\\nimport { \\n FileListingOptionsSchema, \\n FileRemovalOptionsSchema,\\n GitCommitSchema,\\n GitRevertSchema,\\n GitSwitchVersionSchema,\\n InvokeToolSchema,\\n ToolListingOptionsSchema,\\n TerminalCommandSchema \\n} from '../zod_schemas';\\n\\nexport const types = async () => {\\n return generate_interfaces([\\n FileListingOptionsSchema,\\n FileRemovalOptionsSchema,\\n GitCommitSchema,\\n GitRevertSchema,\\n GitSwitchVersionSchema,\\n InvokeToolSchema,\\n ToolListingOptionsSchema,\\n TerminalCommandSchema\\n ], 'src/zod_types.ts');\\n};\"\n },\n {\n \"path\": \"src\\\\commands\\\\list.ts\",\n \"content\": \"import { tools } from '../tools';\\nimport { logger } from '../';\\nimport { ListCommandSchema } from '../zod_schemas';\\nimport { sync as write } from '@plastichub/fs/write';\\nimport { toYargs } from '@plastichub/osr-commons';\\nimport type { Argv } from 'yargs';\\n\\nexport const options = (yargs: Argv) => toYargs(yargs, ListCommandSchema);\\n\\nexport const list = async (argv: any) => {\\n // Initialize tools with current directory\\n const fsTools = tools.fs(process.cwd());\\n const npmTools = tools.npm(process.cwd());\\n const gitTools = tools.git(process.cwd());\\n const terminalTools = tools.terminal(process.cwd());\\n\\n const toolsList = {\\n fs: fsTools.map(tool => ({\\n name: tool.function.name,\\n description: tool.function.description,\\n category: 'fs'\\n })),\\n npm: npmTools.map(tool => ({\\n name: tool.function.name,\\n description: tool.function.description,\\n category: 'npm'\\n })),\\n git: gitTools.map(tool => ({\\n name: tool.function.name,\\n description: tool.function.description,\\n category: 'git'\\n })),\\n terminal: terminalTools.map(tool => ({\\n name: tool.function.name,\\n description: tool.function.description,\\n category: 'terminal'\\n }))\\n };\\n\\n logger.info('Available Tools:\\\\n');\\n \\n logger.info('Filesystem Tools:');\\n fsTools.forEach(tool => {\\n logger.info(` ${tool.function.name}: ${tool.function.description}`);\\n });\\n\\n logger.info('\\\\nNPM Tools:');\\n npmTools.forEach(tool => {\\n logger.info(` ${tool.function.name}: ${tool.function.description}`);\\n });\\n\\n logger.info('\\\\nGit Tools:');\\n gitTools.forEach(tool => {\\n logger.info(` ${tool.function.name}: ${tool.function.description}`);\\n });\\n\\n logger.info('\\\\nTerminal Tools:');\\n terminalTools.forEach(tool => {\\n logger.info(` ${tool.function.name}: ${tool.function.description}`);\\n });\\n\\n if (argv.output) {\\n logger.info(`\\\\nWriting tools list to ${argv.output}`);\\n write(argv.output, JSON.stringify(toolsList, null, 2));\\n }\\n};\"\n },\n {\n \"path\": \"src\\\\commands\\\\invoke.ts\",\n \"content\": \"import { tools } from '../tools';\\nimport { logger } from '../';\\nimport { InvokeToolSchema } from '../zod_schemas';\\nimport { toYargs } from '@plastichub/osr-commons';\\nimport { sync as write } from '@plastichub/fs/write';\\nimport type { Argv } from 'yargs';\\nimport * as path from 'path';\\n\\nconst options = (yargs: Argv) => toYargs(yargs, InvokeToolSchema);\\n\\nexport const invoke = async (argv: any) => {\\n try {\\n const { tools: toolCategory, function: funcName, target, params, output } = argv;\\n \\n // Get tool category\\n const toolSet = tools[toolCategory];\\n if (!toolSet) {\\n logger.error(`Tool category '${toolCategory}' not found`);\\n return;\\n }\\n\\n // Initialize tools with target directory\\n const toolList = toolSet(target);\\n \\n // Find specific function\\n const tool = toolList.find(t => t.function.name === funcName);\\n if (!tool) {\\n logger.error(`Function '${funcName}' not found in ${toolCategory} tools`);\\n return;\\n }\\n\\n // Parse parameters if provided\\n const parameters = params ? JSON.parse(params) : {};\\n \\n // Execute tool function\\n logger.info(`Invoking ${toolCategory}::${funcName}`);\\n const result = await tool.function.function(parameters);\\n \\n // Handle output\\n if (output) {\\n const outputPath = path.isAbsolute(output) ? output : path.join(process.cwd(), output);\\n logger.info(`Writing output to ${outputPath}`);\\n write(outputPath, JSON.stringify(result, null, 2));\\n } else {\\n logger.info('Result:', result);\\n }\\n \\n return result;\\n } catch (error) {\\n logger.error('Error invoking tool:', error);\\n throw error;\\n }\\n};\\n\\nexport { options as invokeOptions };\"\n },\n {\n \"path\": \"src\\\\commands\\\\index.ts\",\n \"content\": \"import type { Argv } from 'yargs';\\nimport { types } from './types';\\nimport { list, options as listOptions } from './list';\\nimport { invoke, invokeOptions } from './invoke';\\nimport { CONFIG_DEFAULT } from '@plastichub/osr-commons';\\nimport { logger } from '../';\\n\\nexport const commands = (yargs: Argv) => {\\n return yargs\\n .command('types', 'Generate TypeScript interfaces from Zod schemas', {}, types)\\n .command('list', 'List all available tools and their descriptions', listOptions, list)\\n .command('invoke', 'Invoke a specific tool function', invokeOptions, invoke)\\n .option('env_key', {\\n type: 'string',\\n description: 'Environment configuration key'\\n })\\n .middleware([(argv) => {\\n const config = CONFIG_DEFAULT(argv.env_key) as any;\\n if (!config) {\\n logger.warn('No config found!');\\n return;\\n }\\n return config;\\n }])\\n .strict()\\n .help();\\n};\"\n }\n]" }, { "role": "user", "content": "Commit all files via git (tool)" }, { "role": "user", "content": "Update readme.md file, with setup instructions and usage (all commands and library functions)" } ], "tools": [ { "type": "function", "function": { "name": "modify_project_files", "description": "Modify existing project files", "parameters": { "type": "object", "properties": { "files": { "type": "array", "items": { "type": "object", "properties": { "path": { "type": "string" }, "content": { "type": "string" } }, "required": [ "path", "content" ] } } }, "required": [ "files" ] } } }, { "type": "function", "function": { "name": "create_project_structure", "description": "Create project structure with files and folders", "parameters": { "type": "object", "properties": { "files": { "type": "array", "items": { "type": "object", "properties": { "path": { "type": "string" }, "content": { "type": "string" } }, "required": [ "path", "content" ] } } }, "required": [ "files" ] } } }, { "type": "function", "function": { "name": "create_file", "description": "Creates a file, given a path and content", "parameters": { "type": "object", "properties": { "file": { "type": "object", "properties": { "path": { "type": "string" }, "content": { "type": "string" } } } }, "required": [ "file" ] } } }, { "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" ] } } }, { "type": "function", "function": { "name": "install_dependency", "description": "Install a dependency using npm", "parameters": { "type": "object", "properties": { "dependencies": { "type": "array", "items": { "type": "string" } } }, "required": [ "dependencies" ] } } }, { "type": "function", "function": { "name": "commit_files_git", "description": "Commit files using git", "parameters": { "type": "object", "properties": { "files": { "type": "array", "items": { "type": "string" } }