Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

scriptmonkey

Package Overview
Dependencies
Maintainers
1
Versions
18
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

scriptmonkey - pypi Package Compare versions

Comparing version
1.4.4
to
2.0.0
+81
-168
PKG-INFO
Metadata-Version: 2.1
Name: scriptmonkey
Version: 1.4.4
Summary: A Python package that generates complex software projects and fixes errors in your code using OpenAI's GPT API.
Version: 2.0.0
Summary: A simple CLI utility for copying files and directory trees to clipboard for easy sharing with LLMs.
Home-page: https://github.com/lukerbs/ScriptMonkey

@@ -9,3 +9,3 @@ Author: Luke Kerbs

License: MIT
Keywords: openai,GPT,AI,project generation,multi-file project,complex project generator,code error fixing,code automation,GPT API,error correction,code assistant,AI coding tools,script monkey,automation,development tools,python tools,code analysis,machine learning,project bootstrap,custom code generation,python package,cursor,devin,copilot,automatic code correction
Keywords: clipboard,file sharing,directory tree,development tools,python tools,LLM helper,code sharing,project structure,file utility,developer tools
Classifier: Programming Language :: Python :: 3

@@ -16,31 +16,16 @@ Classifier: License :: OSI Approved :: MIT License

Description-Content-Type: text/markdown
Requires-Dist: openai
Requires-Dist: pydantic
Requires-Dist: tqdm
Requires-Dist: python-dotenv
Requires-Dist: rich
Requires-Dist: pyperclip
# ScriptMonkey 🐒
ScriptMonkey is an AI-powered CLI tool and Python library that reimagines how projects are built. It doesn’t just generate simple scripts or templates like traditional LLMs—it creates entire, multi-file, multi-directory projects with fully custom code. Complex software projects can be generated in seconds based on your natural language descriptions, providing everything you need, from models and routes to templates and configuration files. With ScriptMonkey, you can instantly bootstrap new ideas or start complex projects without the tedious setup. The tool is perfect for developers looking to quickly prototype, experiment, or build production-ready applications without having to write boilerplate code manually.
ScriptMonkey is a simple CLI utility that helps developers quickly copy files and directory structures to their clipboard in a formatted way. Perfect for sharing code context with LLMs, creating documentation, or getting help with your projects.
Importantly, ScriptMonkey is versatile and can be used to build any type of software project in any programming language. Whether you’re working with Python, JavaScript, Java, C++, or any other language, ScriptMonkey can generate project structures and provide tailored code. Additionally, its context-aware Q&A feature allows you to ask technical questions about projects in any language, with or without providing files for context. You can even use your default editor for longer, multi-line prompts, ensuring that ScriptMonkey can adapt to your specific needs.
## Features
- **Custom Project Generation**: Create entire Python projects, not just boilerplate code. ScriptMonkey generates the specific files and directories you need based on your description.
- **Lightning-Fast Setup**: Complex Python projects can be generated in seconds, saving you time and effort.
- **Automatic Error Detection**: Captures errors during runtime.
- **AI-Powered Fixes**: Uses OpenAI's GPT API to understand and resolve errors.
- **Code Auto-Correction**: Automatically updates your Python files with the fixes.
- **Cross-IDE Compatibility**: Works with any IDE or code editor.
- **Context-Aware Q&A**: Ask questions directly to ChatGPT with or without providing files for context. Get detailed answers with code examples, explanations, and best practices tailored to your needs.
- **File Copying**: Copy one or multiple files to clipboard with clean formatting
- **Directory Tree**: Generate and copy directory structure to clipboard
- **Combined Output**: Copy both files and directory tree together
- **Smart Filtering**: Intelligent directory tree that filters out build artifacts, dependencies, and other non-essential files
- **Cross-Platform**: Works on Windows, macOS, and Linux
## 🚀 Watch the Demo
[![ScriptMonkey Demo](https://img.youtube.com/vi/2zoCDlf0Zf8/maxresdefault.jpg)](https://youtu.be/2zoCDlf0Zf8)
Click the image above or watch the video directly on [YouTube](https://youtu.be/2zoCDlf0Zf8).
## Installation

@@ -56,181 +41,109 @@

### Project Generation with `scriptmonkey` CLI Tool
### Copy Files to Clipboard
ScriptMonkey can generate a complete, custom-coded project structure based on a description you provide. This feature helps you quickly set up new projects with the necessary files and folders.
Copy one or more files to your clipboard with clean formatting:
#### How to Use
```bash
scriptmonkey --files path/to/file1.py path/to/file2.js
```
1. Run the following command in your terminal:
The files will be copied to your clipboard in this format:
```
- - - - - - - - - -
Here are some details about the project.
```bash
scriptmonkey
```
# path/to/file1.py
<content from file1.py>
2. A text editor will open (e.g., `nano`, `vim`, or `notepad` depending on your environment). Follow the on-screen instructions to provide a detailed description of your project.
- - - - - - - - - -
3. Save and close the editor. ScriptMonkey will then:
- Generate a complete project structure based on your description.
- Create directories, code files, and templates.
- Automatically generate a `README.md` with installation instructions and usage details.
# path/to/file2.js
<content from file2.js>
#### Example Project Description Prompt
- - - - - - - - - -
```
I need a Flask-based web application for managing a book library. The application should include:
- User authentication (login, registration, password reset).
- Models for Users, Books, and Authors using SQLAlchemy.
- A REST API with routes for adding, updating, and deleting books and authors.
- An admin dashboard for managing users and viewing statistics.
- HTML templates for user login, book list, and book detail views.
- The database should use PostgreSQL.
- Include environment-specific configurations for development and production.
```
ScriptMonkey will use this description to create a project structure and code files for you in a directory named `generated_project`.
### Copy Directory Tree to Clipboard
### Context-Aware Q&A with `scriptmonkey --ask` CLI Tool
Generate and copy a clean directory tree structure:
ScriptMonkey can help answer your technical questions, whether or not you provide code files for context. This feature allows you to leverage the power of ChatGPT to ask questions about files, clarify concepts, get code reviews, or understand best practices in various programming languages.
```bash
scriptmonkey --tree
```
#### How to Use
This creates an intelligent directory tree that:
- Filters out build artifacts (`node_modules`, `__pycache__`, `.git`, etc.)
- Excludes temporary files (`*.log`, `*.pyc`, `.DS_Store`, etc.)
- Shows important directories as shallow entries (`vendor/`, `build/ [...]`)
- Provides special handling for Rust `target` directories
- **Pass a question directly**:
### Copy Both Files and Tree
For quick, short prompts, you can directly pass your question using the `--ask` parameter:
Combine file contents with directory structure:
```bash
scriptmonkey --ask "What are the best practices for database indexing?"
```
```bash
scriptmonkey --files src/main.py src/utils.py --tree
```
- **Use your default editor for longer prompts**:
This copies both the specified files and the directory tree to your clipboard, giving you complete context for sharing with LLMs or documentation.
If you need to provide a more detailed or multi-line prompt, simply use `--ask` without specifying a question. This will open up your default text editor (e.g., `vim`, `nano`, `notepad`) where you can write out your question or prompt:
## Smart Directory Filtering
```bash
scriptmonkey --ask
```
ScriptMonkey uses intelligent filtering to show you only the important parts of your project:
After you write your question in the editor and save and close it, ScriptMonkey will use the content as the question. This is especially useful for longer or more complex queries that require more explanation.
**Shallow Directories** (shown but contents hidden):
- `node_modules`, `.git`, `build`, `dist`
- `__pycache__`, `.venv`, `vendor`
- `test`, `tests`, `assets`, `img`
- **Ask a question about specific local files**:
**Excluded Files** (completely hidden):
- `*.log`, `*.pyc`, `*.swp`, `.DS_Store`
- `*.class`, `*.o`, `*.dll`, `*.so`
- Build artifacts and temporary files
```bash
scriptmonkey --ask "Can you help me optimize this function?" --files ./path/to/file1.py ./path/to/file2.js
```
**Special Handling**:
- Rust `target/release` directories show filtered contents
- Model directories are treated as shallow
- Test directories are marked but not expanded
The `--files` flag allows you to provide specific files as context for your question. ScriptMonkey will include the contents of these files in its analysis, allowing it to reference the actual code or data you are working with. This is particularly useful for getting detailed feedback on specific code snippets, debugging issues, or seeking advice on how to improve certain parts of your project.
When you use `--files`, ScriptMonkey will read the contents of each provided file, include them in the prompt, and tailor its response based on the combined context of your question and the file contents. This feature ensures that you get precise, context-aware answers, helping you solve code challenges or understand complex concepts more effectively.
## Use Cases
- **Ask a question with a directory tree**:
- **LLM Assistance**: Quickly share your code context with ChatGPT, Claude, or other AI assistants
- **Code Reviews**: Copy relevant files for review discussions
- **Documentation**: Generate clean file listings for documentation
- **Project Sharing**: Share project structure and key files with teammates
- **Debugging Help**: Include relevant code and project structure when asking for help
```bash
scriptmonkey --ask "How do I organize this project better?" --tree
```
## Requirements
- Python 3.6 or later
- Cross-platform clipboard support (automatic)
The `--tree` flag will include a tree representation of the current working directory in the context for your question. This is particularly useful when you want to get feedback on the structure of your codebase or when your question relates to the project organization. It can be used in tandem with the `--files` flag to provide additional context about how those files fit within the larger context of the project.
## Examples
ScriptMonkey will analyze your question and any provided files or the directory tree to give a detailed, markdown-formatted response with explanations and code suggestions, if applicable. This feature is great for in-depth guidance on code optimization, architecture, or general programming questions.
**Copy a single Python file:**
```bash
scriptmonkey --files main.py
```
### Copy Key Files and Project Details with `--copy`
**Copy multiple configuration files:**
```bash
scriptmonkey --files config.json requirements.txt .env.example
```
ScriptMonkey's new `--copy` feature is designed to streamline the process of copying critical code files and project structure details into your clipboard, making it easier to ask questions to LLMs like ChatGPT or Claude. This feature formats the copied content in a neat way that includes file contents and the directory tree, making it simple to paste into a conversation for contextual help.
#### How to Use
- **Copy file contents directly**:
You can use the --copy flag to quickly copy the contents of specified files into your clipboard, neatly formatted for easy sharing with an LLM. When combined with the --files flag, ScriptMonkey will copy the contents of the selected files along with a complete directory tree of your project. This provides additional context, helping LLMs better understand your project’s structure:
```bash
scriptmonkey --copy --files path/to/file1.py path/to/file2.js
```
Your files and project directory tree are automatically copied to your clipboard in the format:
```
- - - - - - - - - -
Here are some details about the project.
# path/to/file1.py
<content from file1.py>
- - - - - - - - - -
# path/to/file2.js
<content from file2.js>
- - - - - - - - - -
# PROJECT TREE
<directory structure>
```
### Error Handling with `scriptmonkey.run()`
ScriptMonkey doesn't just build projects; it also makes debugging a breeze.
1. Import `scriptmonkey` in your Python script.
2. Call `scriptmonkey.run()` to activate the error handler.
3. Run your code, and let ScriptMonkey handle any errors that occur.
#### Example
```python
import scriptmonkey
# Enable ScriptMonkey's error handler
scriptmonkey.run()
# Intentional error for testing
def add(a, b):
return a + b # This will fail if b is a string
print(add(2, "3")) # ScriptMonkey will automatically fix this error and update the file.
**Just the directory tree:**
```bash
scriptmonkey --tree
```
Once an error occurs, ScriptMonkey will:
1. Detect the error.
2. Send the error and code to OpenAI for analysis.
3. Provide a solution and automatically update the file with the corrected code.
### Setting or Updating Your OpenAI API Key
If you haven't set your OpenAI API key yet or need to update it, you can do so with the following command:
**Everything together:**
```bash
python3 -m scriptmonkey --set-api-key your-api-key
scriptmonkey --files src/*.py --tree
```
This will store the API key in a config locally and use it for all future interactions with OpenAI.
## Legacy Compatibility
## Requirements
- Python 3.6 or later
- An OpenAI API key (follow the steps below if you don't have one)
For users upgrading from ScriptMonkey 1.x: The `scriptmonkey.run()` function is still available but no longer provides error handling functionality. It exists only for backward compatibility and does nothing.
## Obtaining an OpenAI API Key
---
1. Go to the OpenAI website: [OpenAI Platform](https://platform.openai.com/)
2. Sign up or log in to your account.
3. Navigate to the **API keys** section in your account dashboard.
4. Create a new API key and copy it.
## Configuring the API Key for ScriptMonkey
- **Option 1: Environment Variable**
You can set up your API key as an environment variable:
```bash
export OPENAI_API_KEY='your-api-key'
```
- **Option 2: Entering the API Key When Prompted**
If ScriptMonkey does not find an API key in your environment variables, it will prompt you to enter your key. Once entered, it will save the key to a configuration file for future use.
- **Option 3: Using the `--set-api-key` Command**
Use the `--set-api-key` command as shown above to set or update your API key easily.
Let ScriptMonkey take care of your Python errors and project setup so you can focus on building!
**Version 2.0.0** - Simplified for focus and reliability. No more AI dependencies, just pure clipboard utility goodness! 🐒
+78
-161

@@ -1,23 +0,12 @@

# ScriptMonkey 🐒
ScriptMonkey is an AI-powered CLI tool and Python library that reimagines how projects are built. It doesn’t just generate simple scripts or templates like traditional LLMs—it creates entire, multi-file, multi-directory projects with fully custom code. Complex software projects can be generated in seconds based on your natural language descriptions, providing everything you need, from models and routes to templates and configuration files. With ScriptMonkey, you can instantly bootstrap new ideas or start complex projects without the tedious setup. The tool is perfect for developers looking to quickly prototype, experiment, or build production-ready applications without having to write boilerplate code manually.
ScriptMonkey is a simple CLI utility that helps developers quickly copy files and directory structures to their clipboard in a formatted way. Perfect for sharing code context with LLMs, creating documentation, or getting help with your projects.
Importantly, ScriptMonkey is versatile and can be used to build any type of software project in any programming language. Whether you’re working with Python, JavaScript, Java, C++, or any other language, ScriptMonkey can generate project structures and provide tailored code. Additionally, its context-aware Q&A feature allows you to ask technical questions about projects in any language, with or without providing files for context. You can even use your default editor for longer, multi-line prompts, ensuring that ScriptMonkey can adapt to your specific needs.
## Features
- **Custom Project Generation**: Create entire Python projects, not just boilerplate code. ScriptMonkey generates the specific files and directories you need based on your description.
- **Lightning-Fast Setup**: Complex Python projects can be generated in seconds, saving you time and effort.
- **Automatic Error Detection**: Captures errors during runtime.
- **AI-Powered Fixes**: Uses OpenAI's GPT API to understand and resolve errors.
- **Code Auto-Correction**: Automatically updates your Python files with the fixes.
- **Cross-IDE Compatibility**: Works with any IDE or code editor.
- **Context-Aware Q&A**: Ask questions directly to ChatGPT with or without providing files for context. Get detailed answers with code examples, explanations, and best practices tailored to your needs.
- **File Copying**: Copy one or multiple files to clipboard with clean formatting
- **Directory Tree**: Generate and copy directory structure to clipboard
- **Combined Output**: Copy both files and directory tree together
- **Smart Filtering**: Intelligent directory tree that filters out build artifacts, dependencies, and other non-essential files
- **Cross-Platform**: Works on Windows, macOS, and Linux
## 🚀 Watch the Demo
[![ScriptMonkey Demo](https://img.youtube.com/vi/2zoCDlf0Zf8/maxresdefault.jpg)](https://youtu.be/2zoCDlf0Zf8)
Click the image above or watch the video directly on [YouTube](https://youtu.be/2zoCDlf0Zf8).
## Installation

@@ -33,181 +22,109 @@

### Project Generation with `scriptmonkey` CLI Tool
### Copy Files to Clipboard
ScriptMonkey can generate a complete, custom-coded project structure based on a description you provide. This feature helps you quickly set up new projects with the necessary files and folders.
Copy one or more files to your clipboard with clean formatting:
#### How to Use
```bash
scriptmonkey --files path/to/file1.py path/to/file2.js
```
1. Run the following command in your terminal:
The files will be copied to your clipboard in this format:
```
- - - - - - - - - -
Here are some details about the project.
```bash
scriptmonkey
```
# path/to/file1.py
<content from file1.py>
2. A text editor will open (e.g., `nano`, `vim`, or `notepad` depending on your environment). Follow the on-screen instructions to provide a detailed description of your project.
- - - - - - - - - -
3. Save and close the editor. ScriptMonkey will then:
- Generate a complete project structure based on your description.
- Create directories, code files, and templates.
- Automatically generate a `README.md` with installation instructions and usage details.
# path/to/file2.js
<content from file2.js>
#### Example Project Description Prompt
- - - - - - - - - -
```
I need a Flask-based web application for managing a book library. The application should include:
- User authentication (login, registration, password reset).
- Models for Users, Books, and Authors using SQLAlchemy.
- A REST API with routes for adding, updating, and deleting books and authors.
- An admin dashboard for managing users and viewing statistics.
- HTML templates for user login, book list, and book detail views.
- The database should use PostgreSQL.
- Include environment-specific configurations for development and production.
```
ScriptMonkey will use this description to create a project structure and code files for you in a directory named `generated_project`.
### Copy Directory Tree to Clipboard
### Context-Aware Q&A with `scriptmonkey --ask` CLI Tool
Generate and copy a clean directory tree structure:
ScriptMonkey can help answer your technical questions, whether or not you provide code files for context. This feature allows you to leverage the power of ChatGPT to ask questions about files, clarify concepts, get code reviews, or understand best practices in various programming languages.
```bash
scriptmonkey --tree
```
#### How to Use
This creates an intelligent directory tree that:
- Filters out build artifacts (`node_modules`, `__pycache__`, `.git`, etc.)
- Excludes temporary files (`*.log`, `*.pyc`, `.DS_Store`, etc.)
- Shows important directories as shallow entries (`vendor/`, `build/ [...]`)
- Provides special handling for Rust `target` directories
- **Pass a question directly**:
### Copy Both Files and Tree
For quick, short prompts, you can directly pass your question using the `--ask` parameter:
Combine file contents with directory structure:
```bash
scriptmonkey --ask "What are the best practices for database indexing?"
```
```bash
scriptmonkey --files src/main.py src/utils.py --tree
```
- **Use your default editor for longer prompts**:
This copies both the specified files and the directory tree to your clipboard, giving you complete context for sharing with LLMs or documentation.
If you need to provide a more detailed or multi-line prompt, simply use `--ask` without specifying a question. This will open up your default text editor (e.g., `vim`, `nano`, `notepad`) where you can write out your question or prompt:
## Smart Directory Filtering
```bash
scriptmonkey --ask
```
ScriptMonkey uses intelligent filtering to show you only the important parts of your project:
After you write your question in the editor and save and close it, ScriptMonkey will use the content as the question. This is especially useful for longer or more complex queries that require more explanation.
**Shallow Directories** (shown but contents hidden):
- `node_modules`, `.git`, `build`, `dist`
- `__pycache__`, `.venv`, `vendor`
- `test`, `tests`, `assets`, `img`
- **Ask a question about specific local files**:
**Excluded Files** (completely hidden):
- `*.log`, `*.pyc`, `*.swp`, `.DS_Store`
- `*.class`, `*.o`, `*.dll`, `*.so`
- Build artifacts and temporary files
```bash
scriptmonkey --ask "Can you help me optimize this function?" --files ./path/to/file1.py ./path/to/file2.js
```
**Special Handling**:
- Rust `target/release` directories show filtered contents
- Model directories are treated as shallow
- Test directories are marked but not expanded
The `--files` flag allows you to provide specific files as context for your question. ScriptMonkey will include the contents of these files in its analysis, allowing it to reference the actual code or data you are working with. This is particularly useful for getting detailed feedback on specific code snippets, debugging issues, or seeking advice on how to improve certain parts of your project.
When you use `--files`, ScriptMonkey will read the contents of each provided file, include them in the prompt, and tailor its response based on the combined context of your question and the file contents. This feature ensures that you get precise, context-aware answers, helping you solve code challenges or understand complex concepts more effectively.
## Use Cases
- **Ask a question with a directory tree**:
- **LLM Assistance**: Quickly share your code context with ChatGPT, Claude, or other AI assistants
- **Code Reviews**: Copy relevant files for review discussions
- **Documentation**: Generate clean file listings for documentation
- **Project Sharing**: Share project structure and key files with teammates
- **Debugging Help**: Include relevant code and project structure when asking for help
```bash
scriptmonkey --ask "How do I organize this project better?" --tree
```
## Requirements
- Python 3.6 or later
- Cross-platform clipboard support (automatic)
The `--tree` flag will include a tree representation of the current working directory in the context for your question. This is particularly useful when you want to get feedback on the structure of your codebase or when your question relates to the project organization. It can be used in tandem with the `--files` flag to provide additional context about how those files fit within the larger context of the project.
## Examples
ScriptMonkey will analyze your question and any provided files or the directory tree to give a detailed, markdown-formatted response with explanations and code suggestions, if applicable. This feature is great for in-depth guidance on code optimization, architecture, or general programming questions.
**Copy a single Python file:**
```bash
scriptmonkey --files main.py
```
### Copy Key Files and Project Details with `--copy`
**Copy multiple configuration files:**
```bash
scriptmonkey --files config.json requirements.txt .env.example
```
ScriptMonkey's new `--copy` feature is designed to streamline the process of copying critical code files and project structure details into your clipboard, making it easier to ask questions to LLMs like ChatGPT or Claude. This feature formats the copied content in a neat way that includes file contents and the directory tree, making it simple to paste into a conversation for contextual help.
#### How to Use
- **Copy file contents directly**:
You can use the --copy flag to quickly copy the contents of specified files into your clipboard, neatly formatted for easy sharing with an LLM. When combined with the --files flag, ScriptMonkey will copy the contents of the selected files along with a complete directory tree of your project. This provides additional context, helping LLMs better understand your project’s structure:
```bash
scriptmonkey --copy --files path/to/file1.py path/to/file2.js
```
Your files and project directory tree are automatically copied to your clipboard in the format:
```
- - - - - - - - - -
Here are some details about the project.
# path/to/file1.py
<content from file1.py>
- - - - - - - - - -
# path/to/file2.js
<content from file2.js>
- - - - - - - - - -
# PROJECT TREE
<directory structure>
```
### Error Handling with `scriptmonkey.run()`
ScriptMonkey doesn't just build projects; it also makes debugging a breeze.
1. Import `scriptmonkey` in your Python script.
2. Call `scriptmonkey.run()` to activate the error handler.
3. Run your code, and let ScriptMonkey handle any errors that occur.
#### Example
```python
import scriptmonkey
# Enable ScriptMonkey's error handler
scriptmonkey.run()
# Intentional error for testing
def add(a, b):
return a + b # This will fail if b is a string
print(add(2, "3")) # ScriptMonkey will automatically fix this error and update the file.
**Just the directory tree:**
```bash
scriptmonkey --tree
```
Once an error occurs, ScriptMonkey will:
1. Detect the error.
2. Send the error and code to OpenAI for analysis.
3. Provide a solution and automatically update the file with the corrected code.
### Setting or Updating Your OpenAI API Key
If you haven't set your OpenAI API key yet or need to update it, you can do so with the following command:
**Everything together:**
```bash
python3 -m scriptmonkey --set-api-key your-api-key
scriptmonkey --files src/*.py --tree
```
This will store the API key in a config locally and use it for all future interactions with OpenAI.
## Legacy Compatibility
## Requirements
- Python 3.6 or later
- An OpenAI API key (follow the steps below if you don't have one)
For users upgrading from ScriptMonkey 1.x: The `scriptmonkey.run()` function is still available but no longer provides error handling functionality. It exists only for backward compatibility and does nothing.
## Obtaining an OpenAI API Key
---
1. Go to the OpenAI website: [OpenAI Platform](https://platform.openai.com/)
2. Sign up or log in to your account.
3. Navigate to the **API keys** section in your account dashboard.
4. Create a new API key and copy it.
## Configuring the API Key for ScriptMonkey
- **Option 1: Environment Variable**
You can set up your API key as an environment variable:
```bash
export OPENAI_API_KEY='your-api-key'
```
- **Option 2: Entering the API Key When Prompted**
If ScriptMonkey does not find an API key in your environment variables, it will prompt you to enter your key. Once entered, it will save the key to a configuration file for future use.
- **Option 3: Using the `--set-api-key` Command**
Use the `--set-api-key` command as shown above to set or update your API key easily.
Let ScriptMonkey take care of your Python errors and project setup so you can focus on building!
**Version 2.0.0** - Simplified for focus and reliability. No more AI dependencies, just pure clipboard utility goodness! 🐒
Metadata-Version: 2.1
Name: scriptmonkey
Version: 1.4.4
Summary: A Python package that generates complex software projects and fixes errors in your code using OpenAI's GPT API.
Version: 2.0.0
Summary: A simple CLI utility for copying files and directory trees to clipboard for easy sharing with LLMs.
Home-page: https://github.com/lukerbs/ScriptMonkey

@@ -9,3 +9,3 @@ Author: Luke Kerbs

License: MIT
Keywords: openai,GPT,AI,project generation,multi-file project,complex project generator,code error fixing,code automation,GPT API,error correction,code assistant,AI coding tools,script monkey,automation,development tools,python tools,code analysis,machine learning,project bootstrap,custom code generation,python package,cursor,devin,copilot,automatic code correction
Keywords: clipboard,file sharing,directory tree,development tools,python tools,LLM helper,code sharing,project structure,file utility,developer tools
Classifier: Programming Language :: Python :: 3

@@ -16,31 +16,16 @@ Classifier: License :: OSI Approved :: MIT License

Description-Content-Type: text/markdown
Requires-Dist: openai
Requires-Dist: pydantic
Requires-Dist: tqdm
Requires-Dist: python-dotenv
Requires-Dist: rich
Requires-Dist: pyperclip
# ScriptMonkey 🐒
ScriptMonkey is an AI-powered CLI tool and Python library that reimagines how projects are built. It doesn’t just generate simple scripts or templates like traditional LLMs—it creates entire, multi-file, multi-directory projects with fully custom code. Complex software projects can be generated in seconds based on your natural language descriptions, providing everything you need, from models and routes to templates and configuration files. With ScriptMonkey, you can instantly bootstrap new ideas or start complex projects without the tedious setup. The tool is perfect for developers looking to quickly prototype, experiment, or build production-ready applications without having to write boilerplate code manually.
ScriptMonkey is a simple CLI utility that helps developers quickly copy files and directory structures to their clipboard in a formatted way. Perfect for sharing code context with LLMs, creating documentation, or getting help with your projects.
Importantly, ScriptMonkey is versatile and can be used to build any type of software project in any programming language. Whether you’re working with Python, JavaScript, Java, C++, or any other language, ScriptMonkey can generate project structures and provide tailored code. Additionally, its context-aware Q&A feature allows you to ask technical questions about projects in any language, with or without providing files for context. You can even use your default editor for longer, multi-line prompts, ensuring that ScriptMonkey can adapt to your specific needs.
## Features
- **Custom Project Generation**: Create entire Python projects, not just boilerplate code. ScriptMonkey generates the specific files and directories you need based on your description.
- **Lightning-Fast Setup**: Complex Python projects can be generated in seconds, saving you time and effort.
- **Automatic Error Detection**: Captures errors during runtime.
- **AI-Powered Fixes**: Uses OpenAI's GPT API to understand and resolve errors.
- **Code Auto-Correction**: Automatically updates your Python files with the fixes.
- **Cross-IDE Compatibility**: Works with any IDE or code editor.
- **Context-Aware Q&A**: Ask questions directly to ChatGPT with or without providing files for context. Get detailed answers with code examples, explanations, and best practices tailored to your needs.
- **File Copying**: Copy one or multiple files to clipboard with clean formatting
- **Directory Tree**: Generate and copy directory structure to clipboard
- **Combined Output**: Copy both files and directory tree together
- **Smart Filtering**: Intelligent directory tree that filters out build artifacts, dependencies, and other non-essential files
- **Cross-Platform**: Works on Windows, macOS, and Linux
## 🚀 Watch the Demo
[![ScriptMonkey Demo](https://img.youtube.com/vi/2zoCDlf0Zf8/maxresdefault.jpg)](https://youtu.be/2zoCDlf0Zf8)
Click the image above or watch the video directly on [YouTube](https://youtu.be/2zoCDlf0Zf8).
## Installation

@@ -56,181 +41,109 @@

### Project Generation with `scriptmonkey` CLI Tool
### Copy Files to Clipboard
ScriptMonkey can generate a complete, custom-coded project structure based on a description you provide. This feature helps you quickly set up new projects with the necessary files and folders.
Copy one or more files to your clipboard with clean formatting:
#### How to Use
```bash
scriptmonkey --files path/to/file1.py path/to/file2.js
```
1. Run the following command in your terminal:
The files will be copied to your clipboard in this format:
```
- - - - - - - - - -
Here are some details about the project.
```bash
scriptmonkey
```
# path/to/file1.py
<content from file1.py>
2. A text editor will open (e.g., `nano`, `vim`, or `notepad` depending on your environment). Follow the on-screen instructions to provide a detailed description of your project.
- - - - - - - - - -
3. Save and close the editor. ScriptMonkey will then:
- Generate a complete project structure based on your description.
- Create directories, code files, and templates.
- Automatically generate a `README.md` with installation instructions and usage details.
# path/to/file2.js
<content from file2.js>
#### Example Project Description Prompt
- - - - - - - - - -
```
I need a Flask-based web application for managing a book library. The application should include:
- User authentication (login, registration, password reset).
- Models for Users, Books, and Authors using SQLAlchemy.
- A REST API with routes for adding, updating, and deleting books and authors.
- An admin dashboard for managing users and viewing statistics.
- HTML templates for user login, book list, and book detail views.
- The database should use PostgreSQL.
- Include environment-specific configurations for development and production.
```
ScriptMonkey will use this description to create a project structure and code files for you in a directory named `generated_project`.
### Copy Directory Tree to Clipboard
### Context-Aware Q&A with `scriptmonkey --ask` CLI Tool
Generate and copy a clean directory tree structure:
ScriptMonkey can help answer your technical questions, whether or not you provide code files for context. This feature allows you to leverage the power of ChatGPT to ask questions about files, clarify concepts, get code reviews, or understand best practices in various programming languages.
```bash
scriptmonkey --tree
```
#### How to Use
This creates an intelligent directory tree that:
- Filters out build artifacts (`node_modules`, `__pycache__`, `.git`, etc.)
- Excludes temporary files (`*.log`, `*.pyc`, `.DS_Store`, etc.)
- Shows important directories as shallow entries (`vendor/`, `build/ [...]`)
- Provides special handling for Rust `target` directories
- **Pass a question directly**:
### Copy Both Files and Tree
For quick, short prompts, you can directly pass your question using the `--ask` parameter:
Combine file contents with directory structure:
```bash
scriptmonkey --ask "What are the best practices for database indexing?"
```
```bash
scriptmonkey --files src/main.py src/utils.py --tree
```
- **Use your default editor for longer prompts**:
This copies both the specified files and the directory tree to your clipboard, giving you complete context for sharing with LLMs or documentation.
If you need to provide a more detailed or multi-line prompt, simply use `--ask` without specifying a question. This will open up your default text editor (e.g., `vim`, `nano`, `notepad`) where you can write out your question or prompt:
## Smart Directory Filtering
```bash
scriptmonkey --ask
```
ScriptMonkey uses intelligent filtering to show you only the important parts of your project:
After you write your question in the editor and save and close it, ScriptMonkey will use the content as the question. This is especially useful for longer or more complex queries that require more explanation.
**Shallow Directories** (shown but contents hidden):
- `node_modules`, `.git`, `build`, `dist`
- `__pycache__`, `.venv`, `vendor`
- `test`, `tests`, `assets`, `img`
- **Ask a question about specific local files**:
**Excluded Files** (completely hidden):
- `*.log`, `*.pyc`, `*.swp`, `.DS_Store`
- `*.class`, `*.o`, `*.dll`, `*.so`
- Build artifacts and temporary files
```bash
scriptmonkey --ask "Can you help me optimize this function?" --files ./path/to/file1.py ./path/to/file2.js
```
**Special Handling**:
- Rust `target/release` directories show filtered contents
- Model directories are treated as shallow
- Test directories are marked but not expanded
The `--files` flag allows you to provide specific files as context for your question. ScriptMonkey will include the contents of these files in its analysis, allowing it to reference the actual code or data you are working with. This is particularly useful for getting detailed feedback on specific code snippets, debugging issues, or seeking advice on how to improve certain parts of your project.
When you use `--files`, ScriptMonkey will read the contents of each provided file, include them in the prompt, and tailor its response based on the combined context of your question and the file contents. This feature ensures that you get precise, context-aware answers, helping you solve code challenges or understand complex concepts more effectively.
## Use Cases
- **Ask a question with a directory tree**:
- **LLM Assistance**: Quickly share your code context with ChatGPT, Claude, or other AI assistants
- **Code Reviews**: Copy relevant files for review discussions
- **Documentation**: Generate clean file listings for documentation
- **Project Sharing**: Share project structure and key files with teammates
- **Debugging Help**: Include relevant code and project structure when asking for help
```bash
scriptmonkey --ask "How do I organize this project better?" --tree
```
## Requirements
- Python 3.6 or later
- Cross-platform clipboard support (automatic)
The `--tree` flag will include a tree representation of the current working directory in the context for your question. This is particularly useful when you want to get feedback on the structure of your codebase or when your question relates to the project organization. It can be used in tandem with the `--files` flag to provide additional context about how those files fit within the larger context of the project.
## Examples
ScriptMonkey will analyze your question and any provided files or the directory tree to give a detailed, markdown-formatted response with explanations and code suggestions, if applicable. This feature is great for in-depth guidance on code optimization, architecture, or general programming questions.
**Copy a single Python file:**
```bash
scriptmonkey --files main.py
```
### Copy Key Files and Project Details with `--copy`
**Copy multiple configuration files:**
```bash
scriptmonkey --files config.json requirements.txt .env.example
```
ScriptMonkey's new `--copy` feature is designed to streamline the process of copying critical code files and project structure details into your clipboard, making it easier to ask questions to LLMs like ChatGPT or Claude. This feature formats the copied content in a neat way that includes file contents and the directory tree, making it simple to paste into a conversation for contextual help.
#### How to Use
- **Copy file contents directly**:
You can use the --copy flag to quickly copy the contents of specified files into your clipboard, neatly formatted for easy sharing with an LLM. When combined with the --files flag, ScriptMonkey will copy the contents of the selected files along with a complete directory tree of your project. This provides additional context, helping LLMs better understand your project’s structure:
```bash
scriptmonkey --copy --files path/to/file1.py path/to/file2.js
```
Your files and project directory tree are automatically copied to your clipboard in the format:
```
- - - - - - - - - -
Here are some details about the project.
# path/to/file1.py
<content from file1.py>
- - - - - - - - - -
# path/to/file2.js
<content from file2.js>
- - - - - - - - - -
# PROJECT TREE
<directory structure>
```
### Error Handling with `scriptmonkey.run()`
ScriptMonkey doesn't just build projects; it also makes debugging a breeze.
1. Import `scriptmonkey` in your Python script.
2. Call `scriptmonkey.run()` to activate the error handler.
3. Run your code, and let ScriptMonkey handle any errors that occur.
#### Example
```python
import scriptmonkey
# Enable ScriptMonkey's error handler
scriptmonkey.run()
# Intentional error for testing
def add(a, b):
return a + b # This will fail if b is a string
print(add(2, "3")) # ScriptMonkey will automatically fix this error and update the file.
**Just the directory tree:**
```bash
scriptmonkey --tree
```
Once an error occurs, ScriptMonkey will:
1. Detect the error.
2. Send the error and code to OpenAI for analysis.
3. Provide a solution and automatically update the file with the corrected code.
### Setting or Updating Your OpenAI API Key
If you haven't set your OpenAI API key yet or need to update it, you can do so with the following command:
**Everything together:**
```bash
python3 -m scriptmonkey --set-api-key your-api-key
scriptmonkey --files src/*.py --tree
```
This will store the API key in a config locally and use it for all future interactions with OpenAI.
## Legacy Compatibility
## Requirements
- Python 3.6 or later
- An OpenAI API key (follow the steps below if you don't have one)
For users upgrading from ScriptMonkey 1.x: The `scriptmonkey.run()` function is still available but no longer provides error handling functionality. It exists only for backward compatibility and does nothing.
## Obtaining an OpenAI API Key
---
1. Go to the OpenAI website: [OpenAI Platform](https://platform.openai.com/)
2. Sign up or log in to your account.
3. Navigate to the **API keys** section in your account dashboard.
4. Create a new API key and copy it.
## Configuring the API Key for ScriptMonkey
- **Option 1: Environment Variable**
You can set up your API key as an environment variable:
```bash
export OPENAI_API_KEY='your-api-key'
```
- **Option 2: Entering the API Key When Prompted**
If ScriptMonkey does not find an API key in your environment variables, it will prompt you to enter your key. Once entered, it will save the key to a configuration file for future use.
- **Option 3: Using the `--set-api-key` Command**
Use the `--set-api-key` command as shown above to set or update your API key easily.
Let ScriptMonkey take care of your Python errors and project setup so you can focus on building!
**Version 2.0.0** - Simplified for focus and reliability. No more AI dependencies, just pure clipboard utility goodness! 🐒

@@ -1,6 +0,2 @@

openai
pydantic
tqdm
python-dotenv
rich
pyperclip

@@ -5,5 +5,3 @@ README.md

scriptmonkey/__main__.py
scriptmonkey/agents.py
scriptmonkey/core.py
scriptmonkey/scripting.py
scriptmonkey.egg-info/PKG-INFO

@@ -15,14 +13,4 @@ scriptmonkey.egg-info/SOURCES.txt

scriptmonkey.egg-info/top_level.txt
scriptmonkey/openai_client/__init__.py
scriptmonkey/openai_client/basemodels.py
scriptmonkey/openai_client/client.py
scriptmonkey/openai_client/prompting.py
scriptmonkey/openai_client/prompts/fix_error.txt
scriptmonkey/openai_client/prompts/project_description.txt
scriptmonkey/utils/__init__.py
scriptmonkey/utils/fence.py
scriptmonkey/utils/file_handler.py
scriptmonkey/utils/key_manager.py
scriptmonkey/utils/parsers.py
scriptmonkey/utils/tree.py
scriptmonkey/utils/ui.py
scriptmonkey/utils/tree.py
import os
import sys
import time
import argparse
import platform
import traceback
from pprint import pprint
from rich.console import Console
from .utils.ui import Spinner, cli_text_editor
from .utils.key_manager import update_api_key
from .utils.file_handler import read_file, write_file, copy_files_to_clipboard
from .agents import (
ask_gpt_with_files,
generate_project_structure,
build_project,
generate_readme,
)
from .utils.tree import create_tree
from .utils.file_handler import read_file, copy_to_clipboard
from .openai_client.basemodels import ScriptMonkeyResponse
from .openai_client import (
chatgpt_json,
default_prompts,
)
console = Console()
CONFIG_FILE = os.path.expanduser("~/.scriptmonkey_config")
def get_platform():
os_name = platform.system()
os_version = platform.release()
return f"# Operating System: {os_name}, Version: {os_version}\n\n"
def scriptmonkey_exception_handler(exc_type, exc_value, exc_traceback):
if issubclass(exc_type, KeyboardInterrupt):
sys.__excepthook__(exc_type, exc_value, exc_traceback)
return
error_message = "".join(traceback.format_exception(exc_type, exc_value, exc_traceback))
print(f"\n🐒 ScriptMonkey Detected an Error:")
print(error_message, "\n")
frame = traceback.extract_tb(exc_traceback)[-1]
file_path = frame.filename
original_code = read_file(file_path)
content = f"{get_platform()}# Original Code:\n```\n{original_code}\n```\n\n# Error Message:\n{error_message}"
solution = None
with Spinner("🐒 ScriptMonkey is working on a solution"):
solution = chatgpt_json(
instructions=default_prompts.fix_error, content=content, response_format=ScriptMonkeyResponse
)
print(f"\n🐒 ScriptMonkey Fixed It:\nProblem:\n{solution['problem']}\n")
print(f"Suggested Solution:\n{solution['solution']}\n")
corrected_code = solution["corrected_code"].replace("```python", "").replace("```", "")
write_file(file_path, corrected_code)
print(f"🐒 ScriptMonkey automatically fixed your code at: '{file_path}'.")
def run():
sys.excepthook = scriptmonkey_exception_handler
def handle_no_prompt():
print(f"\nNo Prompt Provided (Tip: Did you save before closing the editor?).\n🐒 Quitting ScriptMonkey...\n")
exit()
def main():
parser = argparse.ArgumentParser(description="ScriptMonkey - Generate Python projects and fix code.")
parser.add_argument("--ask", nargs="?", const=True, help="Ask a question to ChatGPT", type=str)
parser.add_argument("--files", nargs="*", help="Paths to files to include in the prompt", type=str)
parser.add_argument("--tree", help="Include a directory tree in the prompt", action="store_true")
parser.add_argument("--set-api-key", help="Set the OpenAI API key", action="store_true")
parser.add_argument(
"--copy", help="Copy the content of the specified files to the clipboard", action="store_true"
) # New --copy flag
parser = argparse.ArgumentParser(description="ScriptMonkey - Copy files and directory trees to clipboard")
parser.add_argument("--files", nargs="*", help="Paths to files to copy to clipboard", type=str)
parser.add_argument("--tree", help="Include directory tree in clipboard", action="store_true")
args = parser.parse_args()
print(f"\n- - 🐒 WELCOME TO SCRIPT MONKEY 🐒 - - -\n")
print(f"\n🐒 ScriptMonkey - File & Tree Clipboard Utility\n")
if args.set_api_key:
# Handle setting the API key
update_api_key()
# Check if any valid arguments were provided
if not args.files and not args.tree:
console.print("[bold red]❌ Please specify --files, --tree, or both.[/bold red]")
parser.print_help()
return
if args.copy:
# Handle the --copy functionality
file_paths = args.files if args.files else []
if not file_paths:
console.print("[bold red]❌ No files specified to copy. Use --files to specify file paths.[/bold red]")
return
include_tree = args.tree
copy_files_to_clipboard(file_paths)
return
# Handle the clipboard functionality
file_paths = args.files if args.files else []
include_tree = args.tree
if args.ask is not None:
# Handle the --ask functionality
# Check if the --ask flag was used without a direct question (e.g., `--ask` alone)
if args.ask is True:
question = cli_text_editor(mode="ASK")
if not question:
handle_no_prompt()
else:
question = args.ask
# Validate that files exist if provided
if file_paths:
for file_path in file_paths:
if not os.path.exists(file_path):
console.print(f"[bold red]❌ File not found: {file_path}[/bold red]")
return
file_paths = args.files if args.files else []
include_tree = args.tree
ask_gpt_with_files(question, file_paths, include_tree)
return
else:
# Handle the build project functionality
print(f"Opening prompt editor... ")
time.sleep(2)
copy_to_clipboard(file_paths, include_tree)
# Step 1: Get multi-line project description from user
project_description = cli_text_editor(mode="BUILD")
if not project_description:
handle_no_prompt()
print(f"Project Description: {project_description}")
# Step 2: Generate the project structure using OpenAI API
project_structure = generate_project_structure(project_description)
print(f"\n🐒 ScriptMonkey created a project blueprint:")
pprint(project_structure)
# Step 3: Create the project structure (directories and files) on the filesystem
print(f"\n🐒 ScriptMonkey is coding...")
build_project(project_structure_response=project_structure, project_description=project_description)
print("\nProject structure creation complete.")
# Step 4: Generate the README.md content based on the project description and structure
readme_content = generate_readme(project_description, project_structure)
readme_path = "./generated_project/README.md"
with open(readme_path, "w") as readme_file:
readme_file.write(readme_content)
print(f"🐒 ScriptMonkey wrote a README.md file at: '{readme_path}'")
return
# Legacy function for backward compatibility (now does nothing)
def run():
"""Legacy function - no longer provides error handling."""
pass

@@ -12,30 +12,54 @@ import os

def copy_files_to_clipboard(file_paths, include_tree=True):
def copy_to_clipboard(file_paths, include_tree=False):
"""
Reads the content from the specified files and copies it to the clipboard in the specified format.
Optionally includes a project directory tree.
Reads content from specified files and/or directory tree and copies to clipboard.
Also prints the output to terminal.
"""
formatted_output = "- - - - - - - - - -\nHere are some details about the project.\n\n"
if not file_paths and not include_tree:
console.print("[bold red]❌ No files or tree specified to copy.[/bold red]")
return
for path in file_paths:
try:
content = read_file(path)
formatted_output += f"# {path}\n{content}\n\n- - - - - - - - - -\n"
except FileNotFoundError:
console.print(f"[bold yellow]Warning: {path} not found. Skipping this file.[/bold yellow]")
except Exception as e:
console.print(f"[bold red]Error reading {path}: {e}[/bold red]")
formatted_output = ""
# Handle files if provided
if file_paths:
formatted_output += "- - - - - - - - - -\nHere are some details about the project.\n\n"
for path in file_paths:
try:
content = read_file(path)
formatted_output += f"# {path}\n{content}\n\n- - - - - - - - - -\n\n"
except FileNotFoundError:
console.print(f"[bold yellow]Warning: {path} not found. Skipping this file.[/bold yellow]")
except Exception as e:
console.print(f"[bold red]Error reading {path}: {e}[/bold red]")
# Include the directory tree if requested
if include_tree:
start_directory = os.getcwd()
dir_name = os.path.basename(start_directory)
tree = create_tree(start_directory)
formatted_output += "- - - - - - - - - -\n\n# PROJECT TREE\n"
formatted_output += f"{tree}\n\n"
if file_paths:
formatted_output += "# PROJECT TREE\n"
formatted_output += f"{dir_name}\n{tree}"
# Copy the formatted output to the clipboard
pyperclip.copy(formatted_output)
console.print("[green]🐒 Content has been copied to the clipboard.[/green]")
# Copy the formatted output to the clipboard and print to terminal
if formatted_output:
pyperclip.copy(formatted_output.strip())
# Print the output to terminal
print(formatted_output.strip())
print() # Add some spacing
# Show what was copied
if file_paths and include_tree:
console.print(f"[green]🐒 Copied {len(file_paths)} file(s) and directory tree to clipboard.[/green]")
elif file_paths:
console.print(f"[green]🐒 Copied {len(file_paths)} file(s) to clipboard.[/green]")
elif include_tree:
console.print("[green]🐒 Copied directory tree to clipboard.[/green]")
else:
console.print("[bold red]❌ Nothing to copy.[/bold red]")
def read_file(path: str) -> str:

@@ -42,0 +66,0 @@ """Loads a file and returns the content.

import os
from collections import defaultdict
# SHALLOW DIRECTORIES (Non-Recursive Scan)
# These directories are shown but their contents are not scanned
SHALLOW_DIRS = {
"node_modules",
".git",
"build",
"dist",
"vendor",
"__pycache__",
"venv",
".venv",
".bundle",
"DerivedData",
"site",
"assets",
"img",
"fonts",
".cache",
# Vendored dependency rules
"deps",
"google",
"pyasn1_modules",
"babel",
"espeak-ng-data",
"templates",
"migrations",
"lib",
"meta",
# Model directory rules
"embedding_models",
"imagegen_models",
"textgen_models",
"tts_models",
"whisper_models",
# Test directory rules
"test",
"tests",
"__tests__",
# Project-specific config/output rules
".erb",
".vscode",
".github",
"release",
# Rust-specific rules
"debug",
"incremental",
}
def create_tree(start_path, prefix="", max_depth=None, current_depth=0, max_files_per_type=5):
# FULL EXCLUSION (Completely Hidden)
# These files/directories are completely hidden from the tree
EXCLUDE_PATTERNS = [
".DS_Store",
"*.log",
"*.swp",
"*.swo",
"*~",
"#*#",
"*.pyc",
"*.class",
"*.o",
"*.dylib",
"*.so",
"*.dll",
"*.a",
".eslintcache",
".prettiercache",
"Thumbs.db",
".gitkeep",
"*.ico",
"*.icns",
"*.patch",
"*.metadata",
"sitemap.xml",
"sitemap.xml.gz",
"*.gguf.lock",
"CACHEDIR.TAG",
# Generated & vendor file rules
"*_pb2.py",
"*_pb2.pyi",
"cacerts.txt",
"*.dat",
"*_dict",
]
# RUST RELEASE EXCLUSION (For target/release)
# These items are hidden within the 'release' directory
RELEASE_EXCLUDE_PATTERNS = {
".cargo-lock",
".fingerprint",
"build",
"deps",
"examples",
"incremental",
}
def create_tree(start_path, prefix="", max_depth=None, current_depth=0):
"""
Generates a directory tree as a string with options to limit files of the same type,
ignore directories, and handle critical code files.
Generates a directory tree as a string with intelligent filtering for source code projects.
Mimics the codetree bash script behavior with shallow directories, exclusions, and special handling.
"""

@@ -15,128 +109,129 @@ # If max_depth is defined and the current depth exceeds it, stop recursion

tree = ""
files = sorted(os.listdir(start_path))
# Group files by their extensions
files_by_extension = defaultdict(list)
for name in files:
if os.path.isdir(os.path.join(start_path, name)):
files_by_extension["<dir>"].append(name)
else:
_, ext = os.path.splitext(name)
files_by_extension[ext].append(name)
try:
all_items = sorted(os.listdir(start_path))
except (OSError, PermissionError):
return ""
# Build a list of files to display
display_files = []
# Filter out excluded items
items_to_process = []
for item in all_items:
if not is_excluded(item):
items_to_process.append(item)
# Add directories first
display_files.extend(sorted(files_by_extension["<dir>"]))
count = len(items_to_process)
# Add files, limiting non-important file types
for ext, ext_files in files_by_extension.items():
if ext == "<dir>":
continue
if ext in important_extensions:
# Include all files of important types
display_files.extend(sorted(ext_files))
for i, item in enumerate(items_to_process):
full_path = os.path.join(start_path, item)
connector = "└── " if i == count - 1 else "├── "
next_prefix = prefix + (" " if i == count - 1 else "│ ")
if os.path.isdir(full_path):
# Special handling for Rust target directory
if item == "target":
tree += prefix + connector + item + "\n"
tree += handle_target_directory(full_path, next_prefix)
elif is_shallow(item):
tree += prefix + connector + item + "/ [...]" + "\n"
else:
tree += prefix + connector + item + "\n"
tree += create_tree(
full_path,
next_prefix,
max_depth=max_depth,
current_depth=current_depth + 1,
)
else:
# Limit the number of files to `max_files_per_type` for non-important types
display_files.extend(sorted(ext_files)[:max_files_per_type])
if len(ext_files) > max_files_per_type:
display_files.append(f"... ({len(ext_files) - max_files_per_type} more {ext} files omitted)")
tree += prefix + connector + item + "\n"
# Iterate over the files and directories to build the tree
for index, name in enumerate(display_files):
path = os.path.join(start_path, name)
return tree
# Skip ignored directories
if os.path.isdir(path) and name in ignored_dirs:
continue
connector = "└── " if index == len(display_files) - 1 else "├── "
tree += prefix + connector + name + "\n"
def handle_target_directory(target_path, prefix):
"""Special handling for Rust target directories"""
tree = ""
release_path = os.path.join(target_path, "release")
debug_path = os.path.join(target_path, "debug")
if os.path.isdir(path):
new_prefix = prefix + (" " if index == len(display_files) - 1 else "│ ")
tree += create_tree(
path,
new_prefix,
max_depth=max_depth,
current_depth=current_depth + 1,
max_files_per_type=max_files_per_type,
)
sub_items = []
if os.path.isdir(release_path):
sub_items.append("release")
if os.path.isdir(debug_path):
sub_items.append("debug")
sub_count = len(sub_items)
j = 0
if os.path.isdir(release_path):
j += 1
release_connector = "└── " if j == sub_count else "├── "
release_next_prefix = prefix + (" " if j == sub_count else "│ ")
tree += prefix + release_connector + "release" + "\n"
# Filter release directory contents
try:
release_contents = sorted(os.listdir(release_path))
release_filtered = []
for r_item in release_contents:
if not is_release_excluded(r_item):
release_filtered.append(r_item)
r_count = len(release_filtered)
for k, r_item in enumerate(release_filtered):
r_item_path = os.path.join(release_path, r_item)
r_connector = "└── " if k == r_count - 1 else "├── "
display_name = r_item
if os.path.isdir(r_item_path):
display_name += "/ [...]"
tree += release_next_prefix + r_connector + display_name + "\n"
except (OSError, PermissionError):
pass
if os.path.isdir(debug_path):
j += 1
debug_connector = "└── " if j == sub_count else "├── "
tree += prefix + debug_connector + "debug/ [...]" + "\n"
return tree
ignored_dirs = {
"venv",
".venv",
"dist",
"build",
"__pycache__",
"node_modules",
".next",
"out",
".nuxt",
"public",
"jspm_packages",
".parcel-cache",
".vercel",
"target",
".gradle",
".mvn",
"bin",
"obj",
"coverage",
"vendor",
"storage",
"cache",
".git",
".idea",
".vscode",
".DS_Store",
"logs",
"log",
"tmp",
"temp",
".angular",
".bundle",
"vendor/bundle",
"htmlcov",
".mypy_cache",
".pytest_cache",
}
def is_shallow(dir_name):
"""Check if directory should be shown as shallow (contents not scanned)"""
if dir_name in SHALLOW_DIRS:
return True
# Define important file extensions
important_extensions = {
# General programming and scripting languages
".py",
".js",
".ts",
".tsx",
".jsx",
".java",
".cpp",
".c",
".h",
".hpp",
".go",
".rb",
".rs",
".php",
".sh",
".pl",
".swift",
".kt",
".kts",
".dart",
".scala",
".lua",
".r",
".jl",
".cs",
".csx",
".m",
".mm",
".bat",
".cmd",
}
# Check for wildcard patterns
if dir_name.endswith(".egg-info"):
return True
if dir_name.endswith(".dist-info"):
return True
return False
def is_excluded(item_name):
"""Check if item should be completely excluded"""
for pattern in EXCLUDE_PATTERNS:
if pattern.startswith("*") and pattern.endswith("*"):
# Contains pattern
if pattern[1:-1] in item_name:
return True
elif pattern.startswith("*"):
# Ends with pattern
if item_name.endswith(pattern[1:]):
return True
elif pattern.endswith("*"):
# Starts with pattern
if item_name.startswith(pattern[:-1]):
return True
else:
# Exact match
if item_name == pattern:
return True
return False
def is_release_excluded(item_name):
"""Check if item should be excluded from target/release directory"""
return item_name in RELEASE_EXCLUDE_PATTERNS
+11
-27

@@ -5,4 +5,4 @@ from setuptools import setup, find_packages

name="scriptmonkey",
version="1.4.4",
description="A Python package that generates complex software projects and fixes errors in your code using OpenAI's GPT API.",
version="2.0.0",
description="A simple CLI utility for copying files and directory trees to clipboard for easy sharing with LLMs.",
long_description=open("README.md", "r").read(),

@@ -15,3 +15,3 @@ long_description_content_type="text/markdown",

packages=find_packages(),
install_requires=["openai", "pydantic", "tqdm", "python-dotenv", "rich", "pyperclip"],
install_requires=["rich", "pyperclip"],
python_requires=">=3.6",

@@ -29,30 +29,14 @@ entry_points={

keywords=[
"openai",
"GPT",
"AI",
"project generation",
"multi-file project",
"complex project generator",
"code error fixing",
"code automation",
"GPT API",
"error correction",
"code assistant",
"AI coding tools",
"script monkey",
"automation",
"clipboard",
"file sharing",
"directory tree",
"development tools",
"python tools",
"code analysis",
"machine learning",
"project bootstrap",
"custom code generation",
"python package",
"cursor",
"devin",
"copilot",
"automatic code correction",
"LLM helper",
"code sharing",
"project structure",
"file utility",
"developer tools",
],
package_data={"scriptmonkey.openai_client": ["prompts/*.txt"]},
include_package_data=True,
)
import os
from rich.console import Console
from .utils.tree import create_tree
from .utils.file_handler import read_file
from .utils.ui import render_response_with_syntax_highlighting
from .utils.parsers import remove_code_block_lines
from .openai_client.client import chatgpt_json, chatgpt
from .openai_client.basemodels import ProjectStructureResponse
console = Console()
def generate_project_structure(description: str) -> ProjectStructureResponse:
"""Generates the project structure based on the user's project description using OpenAI."""
instructions = (
"Generate a detailed project structure for a multi-level application. The project will be placed directly inside a folder named 'generated_project'."
"\n- Do NOT include 'generated_project/' as part of the paths. All paths should be relative to the root of the project directory, meaning they should start directly with the file or folder names as if they are inside 'generated_project'."
"\n- Provide a list of directories and files with their full relative paths."
"\n- Each directory should end with a '/' to indicate that it is a folder."
"\n- For each file or directory, include a 'description' that explains its purpose."
"\n- If the file is a Python code file, also include a 'functions' list. For each function, include:"
"\n - 'function_name': The name of the function."
"\n - 'description': A description of what the function does."
"\n - 'inputs': A list of the function's expected inputs, including data types."
"\n - 'outputs': A list of the function's expected outputs, including data types."
"\n- Do not include any extra explanations, commentary, or introductory text. Only provide the structured data as requested."
)
# Call the chatgpt_json function to get structured project plan
project_structure = chatgpt_json(
instructions=instructions, content=description, response_format=ProjectStructureResponse
)
return project_structure
def generate_code_for_file(file_description: dict, project_description: str, project_files: list) -> str:
"""
Generates content for a given file based on its description using the chatgpt() function.
Args:
file_description (dict): The description of the file for which content is being generated.
project_description (str): A high-level description of the project's purpose and goals.
project_files (list): List of all project files for context.
Returns:
str: The generated content for the file.
"""
# Gather context about the project goal and other files
context = gather_project_context(project_description, project_files)
# Extract the file extension to inform the content type
file_extension = os.path.splitext(file_description["path"])[1].lower().strip(".")
# Dynamically adjust the content type description based on the file extension
if file_extension:
content_type_description = f"{file_extension.upper()} file content"
else:
content_type_description = "text content"
# Prepare instructions for OpenAI to generate content based on the file description and type
instructions = (
f"Write the complete content for a {content_type_description} that fulfills the following requirements. "
"Consider the context of the entire project when generating the content and make use of imports where available and appropriate."
"Use relevant imports, references, and appropriate formatting or structure where necessary. Do not add extra commentary or explanation. "
"Make sure to return the content directly, without wrapping it in any code fences like triple quotes or backticks ."
"i.e. DO NOT include any triple backtrick wrappers at all for any code, (e.g. ```python<content here>```) just return the code as plain text."
f"\n\nFile Description: {file_description['description']}"
f"\n\n{context}\n"
)
# Include functions for code files (if provided)
if file_description.get("functions"):
instructions += "\n\nFunctions:\n"
for function in file_description["functions"]:
instructions += (
f"- {function['function_name']}: {function['description']} "
f"(Inputs: {function['inputs']}, Outputs: {function['outputs']})\n"
)
# Call the chatgpt function to generate the content
generated_content = chatgpt(prompt=instructions)
# Clean up any unintended code blocks
generated_content = remove_code_block_lines(generated_content)
return generated_content
def build_project(
project_structure_response: dict, project_description: str, base_directory: str = "./generated_project"
):
"""Creates the directories and files for the project and generates code content for all file types."""
# Extract the list of project files for context
project_files = project_structure_response["files"]
# Iterate through each file in the project structure
for project_file in project_files:
file_path = os.path.join(base_directory, project_file["path"].lstrip("/"))
# Check if it's a directory or file (directories end with '/')
if file_path.endswith("/"):
os.makedirs(file_path, exist_ok=True)
print(f"🐒 ScriptMonkey created directory: {file_path}")
else:
os.makedirs(os.path.dirname(file_path), exist_ok=True)
# Generate content for all files, including Python, HTML, JSON, CSS, etc.
generated_content = generate_code_for_file(project_file, project_description, project_files)
# Write the generated content to the file if it doesn't already exist
if not os.path.exists(file_path):
with open(file_path, "w") as f:
f.write(generated_content)
print(f"🐒 ScriptMonkey created file with generated content at: '{file_path}'.")
else:
print(f"File already exists, skipping: {file_path}")
def gather_project_context(project_description: str, project_files: list) -> str:
"""
Gathers a summary of the project goal and all existing files with their key functions or classes.
Args:
project_description (str): A high-level description of the project's purpose and goals.
project_files (list): List of project file descriptions.
Returns:
str: A summary of the project goal and existing modules, classes, and functions.
"""
context = f"Project Goal: {project_description}\n\n"
context += "Project Context:\n"
for file in project_files:
if file["functions"]:
context += f"- In '{file['path']}', the following functions are defined:\n"
for function in file["functions"]:
context += f" - {function['function_name']}: {function['description']} (Inputs: {function['inputs']}, Outputs: {function['outputs']})\n"
else:
context += f"- '{file['path']}' is defined with no specific functions listed.\n"
return context
def generate_readme(description: str, project_structure: dict) -> str:
"""Generates a README.md content based on the project description and structure."""
instructions = (
"Write a complete README.md file based on the following project details. "
"The README should include the project overview, installation instructions, usage guide, file structure summary, key features, and configuration details. "
"Make sure the README is well-structured and formatted using Markdown without wrapping the entire README in backticks or any other non-readme commentary."
"Do not include any commentary, explanations, or text outside of the README content."
f"\n\nProject Description: {description}\n"
f"\nProject Structure: {project_structure}\n"
)
readme_content = chatgpt(prompt=instructions)
readme_content = readme_content.strip("```markdown").strip("```")
return readme_content
def ask_gpt_with_files(question, file_paths, include_tree=False):
"""
Constructs a detailed and flexible prompt for ChatGPT using a question and optionally including content from specified files.
"""
prompt = (
f"### Question:\n"
f"{question}\n\n"
"If I have included any files below, you can use them for additional context for this question. "
"Please analyze the provided files below (if available) as needed and reference them when forming your answer. "
"If the answer involves code, please format any code examples using Markdown with properly labeled language-specific code blocks. "
"Your response should be in Markdown format to preserve readability.\n\n"
)
if file_paths:
prompt += "### Files Provided:\n"
for path in file_paths:
try:
content = read_file(path)
prompt += (
f"## File: {path}\n"
f"The content of the file '{path}' is included below. Use this as context for answering the question:\n\n"
f"```\n{content}\n```\n\n"
)
except FileNotFoundError:
console.print(f"[bold yellow]Warning: {path} not found. Skipping this file.[/bold yellow]")
except Exception as e:
console.print(f"[bold red]Error reading {path}: {e}[/bold red]")
else:
prompt += (
"No specific files have been provided, so please base your response solely on the question above. "
"If the response includes any code examples or technical explanations, please use Markdown formatting with language-specific code blocks for clarity.\n"
)
# Include the directory tree if the flag is set
if include_tree:
start_directory = os.getcwd()
tree = create_tree(start_directory)
prompt += "### Directory Tree:\n"
prompt += f"The directory tree of the current working directory is included below (up to a depth of 6 levels):\n\n```\n{tree}\n```\n\n"
console.print("- - Directory Tree - -")
console.print(tree)
# Output the constructed prompt to the console for transparency
console.rule("🐒 ScriptMonkey is Thinking 🐒")
console.rule()
# Use the OpenAI API to get a response
try:
response = chatgpt(prompt=prompt)
# Display the response using rich markdown and detect code blocks
console.rule("🐒 ANSWER 🐒")
render_response_with_syntax_highlighting(response)
console.print("\n")
console.rule()
except Exception as e:
console.print(f"[bold red]Error using OpenAI API: {e}[/bold red]")
from .prompting import DefaultPrompts
from .client import chatgpt_json, chatgpt
default_prompts = DefaultPrompts()
from pydantic import BaseModel
from typing import List, Optional
class FunctionDetails(BaseModel):
function_name: str
description: str
inputs: Optional[List[str]] # List of inputs with data types
outputs: Optional[List[str]] # List of outputs with data types
class ProjectFile(BaseModel):
path: str # The full path to the file or directory
description: str # High-level purpose of the directory or file
functions: Optional[List[FunctionDetails]] # List of functions/classes if it's a code file
class ProjectStructureResponse(BaseModel):
files: List[ProjectFile] # List of all files and directories in the project
class ScriptMonkeyResponse(BaseModel):
problem: str # A description of the error/problem
solution: str # The solution to the problem
corrected_code: str # The corrected version of the Python code
import os
from dotenv import load_dotenv
from pydantic import BaseModel
import openai
CONFIG_FILE = os.path.expanduser("~/.scriptmonkey_config")
# Load environment variables from the .env file if present
load_dotenv()
def get_openai_api_key():
# Try to get the API key from environment variables
api_key = os.getenv("OPENAI_API_KEY")
# If not set, check the config file
if not api_key and os.path.exists(CONFIG_FILE):
with open(CONFIG_FILE, "r") as f:
api_key = f.read().strip()
# If still not set, prompt the user for it
if not api_key:
print("It looks like your OpenAI API key isn't set.")
api_key = input("🐒 Please paste your OpenAI API key here and press ENTER: ").strip()
# Save the key to the config file for future use
with open(CONFIG_FILE, "w") as f:
f.write(api_key)
print(f"Your API key has been saved to {CONFIG_FILE} for future use.")
return api_key
# Get the OpenAI API key using the function
OPENAI_API_KEY = get_openai_api_key()
# Initialize the OpenAI client with the obtained API key
client = openai.OpenAI(api_key=OPENAI_API_KEY)
def chatgpt_json(instructions: str, content: str, response_format: BaseModel) -> dict:
"""This function is used to return content from OpenAI Chat Completions API as a structured dictionary response.
Args:
instructions (str): Instructions for the LLM (how the LLM should process the input content).
content (str): Information that the LLM is supposed to process.
response_format (BaseModel): The output format defined by a Pydantic Basemodel.
Returns:
dict: The structured output response from the LLM.
"""
completion = client.beta.chat.completions.parse(
model="gpt-4o-2024-08-06",
messages=[
{"role": "system", "content": instructions},
{"role": "user", "content": content},
],
response_format=response_format,
)
structured_response = completion.choices[0].message.parsed
return structured_response.model_dump()
def chatgpt(prompt: str, model="gpt-4o", max_tokens=None):
"""Function for generating responses to text prompts with OpenAI's ChatGPT API
Args:
prompt (str): The instructions for ChatGPT to respond to
model (str, optional): ChatGPT model to use. Defaults to "gpt-4o".
- List of Available Models: https://platform.openai.com/docs/models/continuous-model-upgrades
max_tokens (int, optional): Optional, the max tokens to be returned by response. Defaults to no limit (i.e. None).
Returns:
str: Returns the response to the prompt as a string value
"""
completion = client.chat.completions.create(
model=model,
max_tokens=max_tokens,
messages=[{"role": "user", "content": prompt}],
)
response = completion.choices[0].message.content
return response
import os
def load_prompt(path: str) -> str:
path = os.path.join(os.path.dirname(__file__), path)
with open(path, "r") as file:
return file.read()
class DefaultPrompts:
def __init__(self):
self.fix_error = load_prompt(path="./prompts/fix_error.txt")
You are a Python programming expert that helps solve Python code errors.
When you fix Python code, your improvements should be well designed and follow Python best practices.
While you are at it, also make improvements like:
- Improving the code structure, formatting, and readability.
- Adding type hints to functions and classes.
- Organizing import statements.
- Leave short comments in the code describing the fix, and always start your explanations of fixes with: "SCRIPTMONKEY: "
NEVER remove any code related to scriptmonkey imports or statements.
- scriptmonkey.run() should always be the first statement in the file after the imports
Return the solution in a structured JSON format.
Build a Flask web application with user authentication, a PostgreSQL database, and an admin dashboard.
import os
from .openai_client import chatgpt
from .utils.parsers import remove_code_block_lines
def generate_code_for_file(file_description: dict, project_description: str, project_files: list) -> str:
"""
Generates content for a given file based on its description using the chatgpt() function.
Args:
file_description (dict): The description of the file for which content is being generated.
project_description (str): A high-level description of the project's purpose and goals.
project_files (list): List of all project files for context.
Returns:
str: The generated content for the file.
"""
# Gather context about the project goal and other files
context = gather_project_context(project_description, project_files)
# Extract the file extension to inform the content type
file_extension = os.path.splitext(file_description["path"])[1].lower().strip(".")
# Dynamically adjust the content type description based on the file extension
if file_extension:
content_type_description = f"{file_extension.upper()} file content"
else:
content_type_description = "text content"
# Prepare instructions for OpenAI to generate content based on the file description and type
instructions = (
f"Write the complete content for a {content_type_description} that fulfills the following requirements. "
"Consider the context of the entire project when generating the content and make use of imports where available and appropriate."
"Use relevant imports, references, and appropriate formatting or structure where necessary. Do not add extra commentary or explanation. "
"Make sure to return the content directly, without wrapping it in any code fences like triple quotes or backticks ."
"i.e. DO NOT include any triple backtrick wrappers at all for any code, (e.g. ```python<content here>```) just return the code as plain text."
f"\n\nFile Description: {file_description['description']}"
f"\n\n{context}\n"
)
# Include functions for code files (if provided)
if file_description.get("functions"):
instructions += "\n\nFunctions:\n"
for function in file_description["functions"]:
instructions += (
f"- {function['function_name']}: {function['description']} "
f"(Inputs: {function['inputs']}, Outputs: {function['outputs']})\n"
)
# Call the chatgpt function to generate the content
generated_content = chatgpt(prompt=instructions)
# Clean up any unintended code blocks
generated_content = remove_code_block_lines(generated_content)
return generated_content
def create_project_structure(
project_structure_response: dict, project_description: str, base_directory: str = "./generated_project"
):
"""Creates the directories and files for the project and generates code content for all file types."""
# Extract the list of project files for context
project_files = project_structure_response["files"]
# Iterate through each file in the project structure
for project_file in project_files:
file_path = os.path.join(base_directory, project_file["path"].lstrip("/"))
# Check if it's a directory or file (directories end with '/')
if file_path.endswith("/"):
os.makedirs(file_path, exist_ok=True)
print(f"🐒 ScriptMonkey created directory: {file_path}")
else:
os.makedirs(os.path.dirname(file_path), exist_ok=True)
# Generate content for all files, including Python, HTML, JSON, CSS, etc.
generated_content = generate_code_for_file(project_file, project_description, project_files)
# Write the generated content to the file if it doesn't already exist
if not os.path.exists(file_path):
with open(file_path, "w") as f:
f.write(generated_content)
print(f"🐒 ScriptMonkey created file with generated content at: '{file_path}'.")
else:
print(f"File already exists, skipping: {file_path}")
def gather_project_context(project_description: str, project_files: list) -> str:
"""
Gathers a summary of the project goal and all existing files with their key functions or classes.
Args:
project_description (str): A high-level description of the project's purpose and goals.
project_files (list): List of project file descriptions.
Returns:
str: A summary of the project goal and existing modules, classes, and functions.
"""
context = f"Project Goal: {project_description}\n\n"
context += "Project Context:\n"
for file in project_files:
if file["functions"]:
context += f"- In '{file['path']}', the following functions are defined:\n"
for function in file["functions"]:
context += f" - {function['function_name']}: {function['description']} (Inputs: {function['inputs']}, Outputs: {function['outputs']})\n"
else:
context += f"- '{file['path']}' is defined with no specific functions listed.\n"
return context
fence_enums = [
"cucumber",
"abap",
"ada",
"ahk",
"apacheconf",
"applescript",
"as",
"as3",
"asy",
"bash",
"bat",
"befunge",
"blitzmax",
"boo",
"brainfuck",
"c",
"cfm",
"cheetah",
"cl",
"clojure",
"cmake",
"coffeescript",
"console",
"control",
"cpp",
"csharp",
"css",
"cython",
"d",
"delphi",
"diff",
"dpatch",
"duel",
"dylan",
"erb",
"erl",
"erlang",
"evoque",
"factor",
"felix",
"fortran",
"gas",
"genshi",
"gitignore",
"glsl",
"gnuplot",
"go",
"groff",
"haml",
"haskell",
"html",
"hx",
"hybris",
"ini",
"io",
"ioke",
"irc",
"jade",
"java",
"js",
"jsp",
"lhs",
"llvm",
"logtalk",
"lua",
"make",
"mako",
"maql",
"mason",
"markdown",
"modelica",
"modula2",
"moocode",
"mupad",
"mxml",
"myghty",
"nasm",
"newspeak",
"objdump",
"objectivec",
"objectivej",
"ocaml",
"ooc",
"perl",
"php",
"postscript",
"pot",
"pov",
"prolog",
"properties",
"protobuf",
"py3tb",
"pytb",
"python",
"r",
"rb",
"rconsole",
"rebol",
"redcode",
"rhtml",
"rst",
"sass",
"scala",
"scaml",
"scheme",
"scss",
"smalltalk",
"smarty",
"sourceslist",
"splus",
"sql",
"sqlite3",
"squidconf",
"ssp",
"tcl",
"tcsh",
"tex",
"text",
"v",
"vala",
"vbnet",
"velocity",
"vim",
"xml",
"xquery",
"xslt",
"yaml",
]
import os
import sys
CONFIG_FILE = os.path.expanduser("~/.scriptmonkey_config")
# - - - - - API KEY MANAGEMENT - - - - -
def save_api_key(api_key: str):
"""Save the OpenAI API key to the configuration file and environment variable."""
with open(CONFIG_FILE, "w") as file:
file.write(api_key)
os.environ["OPENAI_API_KEY"] = api_key
print(f"✅ OpenAI API key saved to {CONFIG_FILE}.")
def get_openai_api_key() -> str:
"""Retrieve the OpenAI API key from environment or configuration file."""
api_key = os.getenv("OPENAI_API_KEY")
if not api_key:
# Check for API key in the configuration file
if os.path.exists(CONFIG_FILE):
with open(CONFIG_FILE, "r") as file:
api_key = file.read().strip()
# Prompt user for API key if not found
if not api_key:
print("🐒 ScriptMonkey requires an OpenAI API key to function.")
api_key = input("Please enter your OpenAI API key: ")
if api_key:
save_api_key(api_key)
if not api_key:
print("❌ No API key provided. Exiting ScriptMonkey.")
sys.exit(1)
return api_key
def update_api_key():
"""Prompt the user to update the OpenAI API key."""
api_key = input("Enter the new OpenAI API key: ")
if api_key:
save_api_key(api_key)
print("✅ OpenAI API key updated successfully.")
else:
print("❌ No API key provided. The API key was not updated.")
# - - - - - NEW FEATURES - - - - -
def remove_code_block_lines(input_string):
"""Removes any lines from the input string that contain '```'."""
lines = input_string.splitlines()
filtered_lines = [line for line in lines if "```" not in line]
return "\n".join(filtered_lines)
import re
import os
import sys
import time
import itertools
import platform
import threading
import subprocess
import tempfile
from rich.syntax import Syntax
from rich.console import Console
from rich.markdown import Markdown
console = Console()
class Spinner:
def __init__(self, message="Processing"):
self.spinner = itertools.cycle(["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"])
self.stop_running = threading.Event()
self.spin_thread = None
self.message = message
def spin(self):
while not self.stop_running.is_set():
sys.stdout.write(f"\r{self.message} {next(self.spinner)}")
sys.stdout.flush()
time.sleep(0.1)
sys.stdout.write("\r" + " " * (len(self.message) + 2) + "\r")
sys.stdout.flush()
def __enter__(self):
self.spin_thread = threading.Thread(target=self.spin)
self.spin_thread.start()
def __exit__(self, exc_type, exc_val, exc_tb):
self.stop_running.set()
self.spin_thread.join()
def cli_text_editor(mode: str) -> str:
"""
Opens the user's default text editor for entering multi-line input.
The user is provided with instructions within the temporary file,
adjusted based on the detected editor.
:mode: enums['BUILD', 'ASK']
"""
if mode == "BUILD":
purpose = "Project Builder"
user_prompt = "Please describe your project in detail below."
elif mode == "ASK":
purpose = "Prompt Editor"
user_prompt = "Please write your question down below."
with tempfile.NamedTemporaryFile(suffix=".txt") as temp_file:
# Detect the editor from the environment or default based on the OS
editor = os.environ.get("EDITOR")
# If no editor is set, choose a default based on the platform
if not editor:
if platform.system() == "Windows":
editor = "notepad"
else:
editor = "nano" # Default for Unix-like systems
# Adjust instructions based on the detected editor
if "vim" in editor.lower():
instructions = (
f"!# 🐒 Welcome to ScriptMonkey's {purpose}!\n"
f"!# {user_prompt}\n"
"!# Use 'i' to start editing, and when you're done, press 'Esc',\n"
"!# type ':wq' to save and exit.\n"
"!# (Lines starting with '!#' will be ignored.)\n\n"
)
elif "nano" in editor.lower():
instructions = (
f"!# 🐒 Welcome to ScriptMonkey's {purpose}!\n"
f"!# {user_prompt}\n"
"!# When you're done, press 'Ctrl+O' to save and 'Ctrl+X' to exit.\n"
"!# (Lines starting with '!#' will be ignored.)\n\n"
)
elif "notepad" in editor.lower():
instructions = (
f"!# 🐒 Welcome to ScriptMonkey's {purpose}!\n"
f"!# {user_prompt}\n"
"!# When you're done, save and close the Notepad window.\n"
"!# (Lines starting with '!#' will be ignored.)\n\n"
)
elif "code" in editor.lower():
instructions = (
f"!# 🐒 Welcome to ScriptMonkey's {purpose}!\n"
f"!# {user_prompt}\n"
"!# When you're done, save the file and close the editor window.\n"
"!# (Lines starting with '!#' will be ignored.)\n\n"
)
else:
instructions = (
f"!# 🐒 Welcome to ScriptMonkey's {purpose}!\n"
f"!# {user_prompt}\n"
"!# Save and close the editor when you're done.\n"
"!# (Lines starting with '!#' will be ignored.)\n\n"
)
# Write the instructions to the temporary file
temp_file.write(instructions.encode("utf-8"))
temp_file.flush()
# Open the temporary file in the detected editor
subprocess.call([editor, temp_file.name])
# Read the user's input, ignoring lines starting with '!#'
temp_file.seek(0)
user_input = temp_file.read().decode("utf-8")
user_input = "\n".join(line for line in user_input.splitlines() if not line.startswith("!#"))
return user_input.strip()
def render_response_with_syntax_highlighting(response):
"""
Render a ChatGPT response with syntax highlighting for detected code blocks.
"""
# Regular expression to detect code blocks with a specified language (e.g., ```python)
code_block_pattern = re.compile(r"```(\w+)?\n(.*?)```", re.DOTALL)
last_pos = 0
# Iterate over all detected code blocks
for match in code_block_pattern.finditer(response):
language = match.group(1) or "text" # Default to 'text' if no language is specified
code_content = match.group(2)
# Print any text before the code block as markdown
if match.start() > last_pos:
pre_text = response[last_pos : match.start()]
console.print(Markdown(pre_text))
# Print the code block with syntax highlighting
syntax = Syntax(f"\n{code_content}", language, theme="monokai", line_numbers=False)
console.print("\n")
console.print(syntax)
console.print("\n")
last_pos = match.end()
# Print any remaining text after the last code block
if last_pos < len(response):
console.print(Markdown(response[last_pos:]))