Compare commits

...

18 Commits

Author SHA1 Message Date
7fb8671840 fix: add ignore_files to config 2025-02-14 19:18:51 +01:00
32fcc2622f feat: remove old prompt_chat_limit 2025-02-14 15:26:28 +01:00
a5bad60d8e feat: dont include chatgpt_config.yaml in file list 2025-02-13 11:54:27 +01:00
1deae056b7 feat: change token calculation 2025-02-13 11:49:07 +01:00
07eceb4bee feat: change to token calculation again 2025-02-13 11:42:12 +01:00
216a4f2603 fix: init.lua 2025-02-13 01:57:02 +01:00
0617f5ba5b feat: rename execute_command tool, improve go prompt 2025-02-13 01:27:07 +01:00
51f7c2c66f feat: improve basic prompt 2025-02-13 01:18:42 +01:00
5b972c5c9f feat: add memory bank prompt, rename read_file and edit_file, improve basic prompt 2025-02-13 01:14:58 +01:00
01932be82a fix: missing char 2025-02-09 00:50:05 +01:00
e5f4558df5 feat: make prompt better to include real project name 2025-02-09 00:45:29 +01:00
0f044a625e fix: add function close_existing_buffer_by_name back 2025-02-09 00:14:45 +01:00
ebc0791542 feat: load configuration at each command, so it is not needed to restart nvim on config change 2025-02-09 00:08:10 +01:00
9d72ba46c4 feat: add file appending to prompt 2025-02-09 00:02:40 +01:00
2b9aa5f35f feat: adjust prompt 2025-02-08 23:50:50 +01:00
bf04d2f2fc feat: adjust basic prompt for better clarification 2025-02-08 23:48:00 +01:00
d9a1cf83fc feat: add ignore_files option 2025-02-08 03:16:18 +01:00
d19451ca5c refactor: prompt naming 2025-02-08 02:38:47 +01:00
8 changed files with 325 additions and 168 deletions

View File

@@ -1,8 +1,15 @@
project_name: "chatgpt.vim"
default_prompt_blocks:
- "basic-prompt"
- "basic"
- "secure-coding"
ignore_files:
- "node_modules/"
- "*.log"
- "vendor/"
include_file_contents: true
debug: false
improved_debug: false
@@ -11,16 +18,12 @@ interactive_file_selection: false
partial_acceptance: false
enable_debug_commands: true
prompt_char_limit: 300000
enable_chunking: false
enable_step_by_step: true
auto_lint: true
# New tool auto-accept config
tool_auto_accept:
readFile: true
editFile: true
read_file: true
edit_file: true
replace_in_file: true
executeCommand: false
# If you set any of these to true, it will auto accept them without prompting.
# 'executeCommand' should remain false by default unless you're certain it's safe.
execute_command: false

View File

@@ -57,7 +57,7 @@ function M.load()
initial_prompt = "",
directories = { "." },
default_prompt_blocks = {},
prompt_char_limit = 300000,
-- Removed prompt_char_limit
project_name = "",
debug = false,
initial_files = {},
@@ -73,10 +73,10 @@ function M.load()
auto_lint = false,
tool_auto_accept = {
readFile = false,
editFile = false,
read_file = false,
edit_file = false,
replace_in_file = false,
executeCommand = false,
execute_command = false,
}
}
@@ -87,6 +87,7 @@ function M.load()
"No config file found (tried .chatgpt_config.yaml, chatgpt_config.yaml). Using defaults.",
vim.log.levels.WARN
)
config.max_token = 2048
return config
end
@@ -108,9 +109,6 @@ function M.load()
if type(result.default_prompt_blocks) == "table" then
config.default_prompt_blocks = result.default_prompt_blocks
end
if type(result.prompt_char_limit) == "number" then
config.prompt_char_limit = result.prompt_char_limit
end
if type(result.project_name) == "string" then
config.project_name = result.project_name
end
@@ -120,9 +118,12 @@ function M.load()
if type(result.initial_files) == "table" then
config.initial_files = result.initial_files
end
if type(result.include_file_contents) == "boolean" then -- LOAD NEW FLAG
if type(result.include_file_contents) == "boolean" then
config.include_file_contents = result.include_file_contents
end
if type(result.ignore_files) == "table" then
config.ignore_files = result.ignore_files
end
if type(result.preview_changes) == "boolean" then
config.preview_changes = result.preview_changes
end
@@ -153,10 +154,17 @@ function M.load()
end
end
end
if type(result.max_token) == "number" then
config.max_token = result.max_token
else
config.max_token = 2048
end
end
end
else
config.initial_prompt = "You are a coding assistant who receives a project's context and user instructions..."
config.max_token = 2048
end
-- Merge default prompt blocks

View File

@@ -131,6 +131,11 @@ end
function M.get_project_files(directories, conf)
local root = vim.fn.getcwd()
local ignore_patterns = load_gitignore_patterns(root, conf)
if conf.ignore_files then
for _, pattern in ipairs(conf.ignore_files) do
table.insert(ignore_patterns, gitignore_to_lua_pattern(pattern))
end
end
local all_files = {}
for _, dir in ipairs(directories) do
local abs_dir = dir
@@ -143,8 +148,10 @@ function M.get_project_files(directories, conf)
local rel_files = {}
for _, f in ipairs(all_files) do
local rel = vim.fn.fnamemodify(f, ":.")
if not rel:match("^%.?chatgpt_config%.yaml$") then
table.insert(rel_files, rel)
end
end
if conf.debug then
vim.api.nvim_out_write("[chatgpt_nvim:context] Found " .. #rel_files .. " project files.\n")
@@ -191,13 +198,7 @@ function M.get_project_prompt(directories, conf)
if conf.include_file_contents then
local files = M.get_project_files(directories, conf)
local contents = M.get_file_contents(files, conf)
local total_chars = #contents
if total_chars > conf.prompt_char_limit then
vim.notify("Total file contents (" .. total_chars .. " characters) exceed the prompt limit (" .. conf.prompt_char_limit .. "). Please disable 'include_file_contents' in your config.", vim.log.levels.ERROR)
return structure
else
return structure .. "\n" .. contents
end
else
return structure
end

View File

@@ -54,11 +54,12 @@ local function read_file(path)
return data
end
local function close_existing_buffer_by_name(pattern)
for _, b in ipairs(vim.api.nvim_list_bufs()) do
local name = vim.api.nvim_buf_get_name(b)
if name:match(pattern) then
vim.api.nvim_buf_delete(b, { force = true })
-- Added function to close existing buffers matching a name pattern.
local function close_existing_buffer_by_name(name_pattern)
for _, buf in ipairs(vim.api.nvim_list_bufs()) do
local buf_name = vim.api.nvim_buf_get_name(buf)
if buf_name:match(name_pattern) then
vim.api.nvim_buf_delete(buf, {force = true})
end
end
end
@@ -101,7 +102,7 @@ local function build_prompt(user_input, dirs, conf)
task_lines[#task_lines+1] = "</task>\n"
table.insert(final_sections, table.concat(task_lines, "\n"))
-- 4) <file_content path="...">
-- 4) <file_content path="..."> from initial_files
local file_content_blocks = {}
for _, file_path in ipairs(initial_files) do
local full_path = root .. "/" .. file_path
@@ -118,6 +119,39 @@ local function build_prompt(user_input, dirs, conf)
table.insert(final_sections, table.concat(file_content_blocks, "\n\n"))
end
-- 4.1) Dynamic file inclusion via @ operator in user_input
local dynamic_files = {}
for file in user_input:gmatch("@([^%s]+)") do
if file ~= "chatgpt_config.yaml" and file ~= ".chatgpt_config.yaml" then
local already_included = false
for _, existing in ipairs(initial_files) do
if existing == file then
already_included = true
break
end
end
if not already_included then
table.insert(dynamic_files, file)
end
end
end
local dynamic_file_blocks = {}
for _, file in ipairs(dynamic_files) do
local full_path = root .. "/" .. file
if is_subpath(root, full_path) then
local fdata = read_file(full_path)
if fdata then
dynamic_file_blocks[#dynamic_file_blocks+1] = string.format(
"<file_content path=\"%s\">\n%s\n</file_content>", file, fdata
)
end
end
end
if #dynamic_file_blocks > 0 then
table.insert(final_sections, table.concat(dynamic_file_blocks, "\n\n"))
end
-- 5) <environment_details>
local env_lines = {}
env_lines[#env_lines+1] = "<environment_details>"
@@ -133,7 +167,6 @@ local function build_prompt(user_input, dirs, conf)
env_lines[#env_lines+1] = os.date("%x, %X (%Z)")
env_lines[#env_lines+1] = ""
env_lines[#env_lines+1] = "# Current Working Directory (" .. root .. ") Files"
-- Using the new get_project_prompt function instead of get_project_structure.
env_lines[#env_lines+1] = context.get_project_prompt(dirs, conf) or ""
env_lines[#env_lines+1] = ""
env_lines[#env_lines+1] = "# Current Mode"
@@ -141,22 +174,33 @@ local function build_prompt(user_input, dirs, conf)
env_lines[#env_lines+1] = "</environment_details>"
table.insert(final_sections, table.concat(env_lines, "\n"))
return table.concat(final_sections, "\n\n")
local final_prompt = table.concat(final_sections, "\n\n")
final_prompt = final_prompt:gsub("%chatgpt.vim%", conf.project_name)
return final_prompt
end
local function estimate_token_count(text)
local token_count = 0
for chunk in text:gmatch("%S+") do
for token in chunk:gmatch("(%w+|%p+)") do
token_count = token_count + 1
end
end
return token_count
end
local function handle_step_by_step_if_needed(prompt, conf)
local length = #prompt
local limit = conf.prompt_char_limit or 8000
if (not conf.enable_step_by_step) or (length <= limit) then
local token_count = estimate_token_count(prompt)
local limit = conf.max_token or 2048
if (not conf.enable_step_by_step) or (token_count <= limit) then
return { prompt }
end
return { prompts["step-prompt"] }
end
------------------------------------------------------------------------------
-- :ChatGPT
------------------------------------------------------------------------------
local function run_chatgpt_command()
package.loaded["chatgpt_nvim.config"] = nil
local config = require("chatgpt_nvim.config")
local conf = config.load()
ui.setup_ui(conf)
ui.debug_log("Running :ChatGPT command.")
@@ -172,6 +216,7 @@ local function run_chatgpt_command()
local bufnr = vim.api.nvim_create_buf(false, false)
vim.api.nvim_buf_set_name(bufnr, "ChatGPT_Prompt.md")
vim.api.nvim_buf_set_option(bufnr, "filetype", "markdown")
vim.api.nvim_buf_set_option(bufnr, "omnifunc", "v:lua.chatgpt_file_complete")
vim.api.nvim_buf_set_option(bufnr, "bufhidden", "wipe")
vim.api.nvim_buf_set_option(bufnr, "buftype", "")
vim.api.nvim_buf_set_option(bufnr, "modifiable", true)
@@ -179,6 +224,7 @@ local function run_chatgpt_command()
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, {
"# Enter your main user prompt (task) below.",
"",
"You can include files by typing @filename in your prompt.",
"Save & close with :wq, :x, or :bd to finalize your prompt."
})
@@ -220,10 +266,9 @@ local function run_chatgpt_command()
vim.cmd("buffer " .. bufnr)
end
------------------------------------------------------------------------------
-- :ChatGPTPaste
------------------------------------------------------------------------------
local function run_chatgpt_paste_command()
package.loaded["chatgpt_nvim.config"] = nil
local config = require("chatgpt_nvim.config")
local conf = config.load()
ui.setup_ui(conf)
ui.debug_log("Running :ChatGPTPaste command.")
@@ -239,9 +284,7 @@ local function run_chatgpt_paste_command()
return
end
-- Check if we have tools
if data.tools then
-- Must also verify project name
if not data.project_name or data.project_name ~= conf.project_name then
vim.api.nvim_err_writeln("Project name mismatch or missing. Aborting tool usage.")
return
@@ -253,7 +296,6 @@ local function run_chatgpt_paste_command()
return
end
-- If we see project_name & files => older YAML style. We handle it but it's discouraged now.
if data.project_name and data.files then
if data.project_name ~= conf.project_name then
vim.api.nvim_err_writeln("Project name mismatch. Aborting.")
@@ -320,7 +362,6 @@ local function run_chatgpt_paste_command()
end
end
else
-- Not final => user is requesting more files
local requested_paths = {}
local root = vim.fn.getcwd()
for _, fileinfo in ipairs(data.files) do
@@ -352,16 +393,6 @@ local function run_chatgpt_paste_command()
local length = #prompt
ui.debug_log("Returning requested files. Character count: " .. length)
if length > (conf.prompt_char_limit or 8000) and conf.enable_step_by_step then
local large_step = prompts["step-prompt"]
copy_to_clipboard(large_step)
print("Step-by-step guidance copied to clipboard!")
return
elseif length > (conf.prompt_char_limit or 8000) then
vim.api.nvim_err_writeln("Requested files exceed prompt character limit. No step-by-step support enabled.")
return
end
copy_to_clipboard(prompt)
print("Prompt (with requested files) copied to clipboard! Paste it into ChatGPT.")
end
@@ -370,10 +401,9 @@ local function run_chatgpt_paste_command()
end
end
------------------------------------------------------------------------------
-- :ChatGPTCurrentBuffer
------------------------------------------------------------------------------
local function run_chatgpt_current_buffer_command()
package.loaded["chatgpt_nvim.config"] = nil
local config = require("chatgpt_nvim.config")
local conf = config.load()
ui.setup_ui(conf)
ui.debug_log("Running :ChatGPTCurrentBuffer command.")
@@ -409,11 +439,32 @@ local function run_chatgpt_current_buffer_command()
end
end
------------------------------------------------------------------------------
-- PUBLIC API
------------------------------------------------------------------------------
M.run_chatgpt_command = run_chatgpt_command
M.run_chatgpt_paste_command = run_chatgpt_paste_command
M.run_chatgpt_current_buffer_command = run_chatgpt_current_buffer_command
function _G.chatgpt_file_complete(findstart, base)
if findstart == 1 then
local line = vim.fn.getline('.')
local col = vim.fn.col('.')
local start = line:sub(1, col):find("@[^%s]*$")
if start then
return start - 1
else
return -1
end
else
local conf = config.load()
local files = context.get_project_files({'.'}, conf)
local completions = {}
local esc_base = base:gsub("([^%w])", "%%%1")
for _, f in ipairs(files) do
if f:match("^" .. esc_base) then
table.insert(completions, f)
end
end
return completions
end
end
return M

View File

@@ -1,5 +1,82 @@
local M = {
["solidjs-development"] = [[
["memory-bank"] = [[
# Memory Bank
You are Cline, an expert software engineer with a unique constraint: your memory periodically resets completely. This isn't a bug - it's what makes you maintain perfect documentation. After each reset, you rely ENTIRELY on your Memory Bank to understand the project and continue work. Without proper documentation, you cannot function effectively.
## Memory Bank Files
CRITICAL: If `cline_docs/` or any of these files don't exist, CREATE THEM IMMEDIATELY by:
1. Reading all provided documentation
2. Asking user for ANY missing information
3. Creating files with verified information only
4. Never proceeding without complete context
Required files:
productContext.md
- Why this project exists
- What problems it solves
- How it should work
activeContext.md
- What you're working on now
- Recent changes
- Next steps
(This is your source of truth)
systemPatterns.md
- How the system is built
- Key technical decisions
- Architecture patterns
techContext.md
- Technologies used
- Development setup
- Technical constraints
progress.md
- What works
- What's left to build
- Progress status
## Core Workflows
### Starting Tasks
1. Check for Memory Bank files
2. If ANY files missing, stop and create them
3. Read ALL files before proceeding
4. Verify you have complete context
5. Begin development. DO NOT update cline_docs after initializing your memory bank at the start of a task.
### During Development
1. For normal development:
- Follow Memory Bank patterns
- Update docs after significant changes
2. Say `[MEMORY BANK: ACTIVE]` at the beginning of every tool use.
### Memory Bank Updates
When user says "update memory bank":
1. This means imminent memory reset
2. Document EVERYTHING about current state
3. Make next steps crystal clear
4. Complete current task
Remember: After every memory reset, you begin completely fresh. Your only link to previous work is the Memory Bank. Maintain it as if your functionality depends on it - because it does.
]],
["solidjs"] = [[
### SolidJS Development Guidelines
You are helping me develop a large SolidJS application. Please keep the following points in mind when generating or explaining code:
@@ -73,7 +150,7 @@ local M = {
Please follow these guidelines to ensure the generated or explained code aligns well with SolidJS best practices for large, maintainable projects.
]],
["nodejs-development"] = [[
["nodejs"] = [[
You are helping me develop a large Node.js application. Please keep the following points in mind when generating or explaining code:
1. **Project & Folder Structure**
@@ -161,16 +238,17 @@ local M = {
- If you modify existing files, specify precisely which lines or sections have changed, and why.
Please follow these guidelines to ensure the generated or explained code aligns well with Node.js best practices for large, maintainable projects.
]]
["go-development"] = [[
]],
["go"] = [[
### Go Development Guidelines
You are helping me develop a large Go (Golang) project. Please keep the following points in mind when generating or explaining code:
1. **Go Modules**
1. **Go Modules & Dependency Management**
- Use a single `go.mod` file at the project root for module management.
- Ensure you use proper import paths based on the module name.
- If you refer to internal packages, use relative paths consistent with the modules structure (e.g., `moduleName/internal/packageA`).
- **Use the execute_command Tool for Dependencies:** Instead of manually editing version numbers in `go.mod`, please utilize the `execute_command` tool to run dependency commands (such as `go get`) to automatically fetch and update dependencies. This ensures that the correct versions are used without relying on manually provided values.
2. **Package Structure**
- Each folder should contain exactly one package.
@@ -210,12 +288,10 @@ local M = {
6. **Output Format**
- Present any generated source code as well-organized Go files, respecting the single-package-per-folder rule.
- When explaining your reasoning, include any relevant architectural trade-offs and rationale (e.g., “I placed function X in package Y to keep the domain-specific logic separate from the main execution flow.”).
- If you modify an existing file, specify precisely which changes or additions you are making.
Please follow these guidelines to ensure the generated or explained code aligns well with Golangs best practices for large, modular projects.
- When explaining your reasoning, include any relevant architectural trade-offs and rationale (e.g., “I placed function X in package `my_lib` to keep the business logic separate from the command-line interface.”).
- If you modify existing files, specify precisely which changes or additions you are making.
]],
["typo3-development"] = [[
["typo3"] = [[
### TYPO3 Development Guidelines
You are helping me develop a large TYPO3 project. Please keep the following points in mind when generating or explaining code:
@@ -277,10 +353,8 @@ local M = {
- Clearly indicate where each file should be placed in the TYPO3 directory layout.
- When explaining your reasoning, include any relevant architectural decisions (e.g., “I created a separate extension for blog functionality to keep it isolated from the sites main configuration.”).
- If you modify or extend an existing file, specify precisely which changes or additions you are making.
Please follow these guidelines to ensure the generated or explained code aligns well with TYPO3s best practices for large, maintainable projects.
]],
["rust-development"] = [[
["rust"] = [[
### Rust Development Guidelines
You are helping me develop a large Rust project. Please keep the following points in mind when generating or explaining code:
@@ -320,14 +394,14 @@ local M = {
4. **Coding & Documentation Best Practices**
- Write **idiomatic Rust** code:
- Use `cargo fmt` (formatting) and `cargo clippy` (linter) to maintain consistency and quality.
- Use `?` operator for error handling, prefer `Result<T, E>` over panicking unless absolutely necessary.
- Use the `?` operator for error handling, preferring `Result<T, E>` over panicking unless absolutely necessary.
- Document your code using [Rustdoc](https://doc.rust-lang.org/rustdoc/) comments (`///` for public API) and provide examples when relevant.
- Write **unit tests** alongside the code (in `src/` files) and **integration tests** in a dedicated `tests/` folder.
- Keep functions short, focused, and ensure they have well-defined responsibilities.
5. **Reusability & Shared Code**
- Place common or reusable functionality into a dedicated **library** crate.
- Ensure that crates depending on shared code add the appropriate `[dependencies]` or `[dev-dependencies]` in their `Cargo.toml`.
- Ensure that crates depending on shared code add the appropriate `[dependencies]` or `[dev-dependencies]` in their Cargo.toml.
- Use the Rust standard library whenever possible before introducing external dependencies.
6. **Error Handling & Logging**
@@ -339,22 +413,95 @@ local M = {
- Present generated source code as well-organized Rust files, respecting the single main library or binary per crate (`lib.rs` or `main.rs`).
- When explaining your reasoning, include any architectural or design decisions (e.g., “I placed function X in crate `my_lib` to keep the business logic separate from the command-line interface.”).
- If you modify existing files, specify precisely which lines or sections have changed.
Please follow these guidelines to ensure the generated or explained code aligns well with Rust best practices for large, modular projects.
]],
["basic-prompt"] = [[
["basic"] = [[
### Basic Prompt
You are assisting me in a coding workflow for a project (e.g., "my_project"). Whenever you need to inspect or modify files, or execute commands, you must provide both:
You are assisting me in a coding workflow for a project (e.g., "%PROJECT_NAME%"). **Every time you inspect, modify, or execute operations on files, you must strictly follow the YAML format described below.** Under no circumstances should you output file operations in plain text or deviate from this structure.
1. `project_name: "<actual_project_name>"` (matching the real project name)
2. A `tools:` array describing the operations you want to perform.
#### Mandatory Guidelines
**Example** (substitute `<actual_project_name>` with the real name):
1. **YAML-Only File Operations**
- **All operations must be provided within one single YAML block** that includes both the `project_name` and the `tools` array.
- If you need to ask questions or request clarifications, do so only in plain text separate from YAML. **Never include non-YAML tool commands.**
2. **Include the Project Name**
- Always include:
```yaml
project_name: "my_project"
project_name: "%PROJECT_NAME%"
```
This must be part of every YAML block you generate.
3. **Operations Must Appear in the Tools Array**
- List all actions (e.g., reading, editing, replacing, executing commands) as items in the `tools:` array. If multiple actions are needed, include them sequentially within the same YAML block.
4. **Read Before Write Rule**
- **Do not perform any write operations (using `edit_file` or `replace_in_file`) on an existing file unless you have already read its content in the current session using a `read_file` operation.**
- For new files (files that do not yet exist in the project), this rule does not apply.
- If yo already got the file contents in the first prompt, this rule does not apply.
- **Never** mix read_file with edit_file or replace_in_file in the same YAML block.
5. **File Inspection Before Modification**
- When you need to inspect a files contents, always use the following YAML format:
```yaml
project_name: "%PROJECT_NAME%"
tools:
- tool: "readFile"
- tool: "read_file"
path: "relative/path/to/file"
```
- Use the information from this operation to decide if and how to modify the file.
6. **Modifying Files**
- To modify a file that you have already read, use:
```yaml
project_name: "%PROJECT_NAME%"
tools:
- tool: "edit_file"
path: "relative/path/to/file"
content: |
# Full updated file content here
```
- Alternatively, for incremental changes, use:
```yaml
project_name: "%PROJECT_NAME%"
tools:
- tool: "replace_in_file"
path: "relative/path/to/file"
replacements:
- search: "old text"
replace: "new text"
```
7. **Executing Commands**
- To run any shell command (e.g., testing, listing files), use:
```yaml
project_name: "%PROJECT_NAME%"
tools:
- tool: "execute_command"
command: "shell command here"
```
8. **General Process**
- **Step 1: Gather Context / Ask Questions**
If any detail is unclear (such as file content or operation intent), ask your clarifying questions in plain text (not in YAML).
- **Step 2: Inspect Files**
Always use `read_file` to check file content before modifying.
- **Step 3: Repeat Steps 1 & 2 as Needed**
If further context is required, ask questions and read files again.
- **Step 4: Make Changes**
Only after reading the file, proceed to use `edit_file` or `replace_in_file`.
- **Step 5: Execute Commands if Needed**
Use `execute_command` as necessary, always within the YAML block.
- **Step 6: Tell that request is complete**
Once all operations are done, confirm that the request is complete with a little summary.
- **Step 7: Repeat other steps as necessary**
#### Example YAML Block
```yaml
project_name: "%PROJECT_NAME%"
tools:
- tool: "read_file"
path: "relative/path/to/file"
- tool: "replace_in_file"
@@ -363,77 +510,24 @@ local M = {
- search: "old text"
replace: "new text"
- tool: "editFile"
- tool: "edit_file"
path: "relative/path/to/file"
content: |
# Full updated file content here
- tool: "executeCommand"
- tool: "execute_command"
command: "ls -la"
```
**Key Points**:
- Always include `project_name: "<actual_project_name>"` in the same YAML as `tools`.
- If you only need one tool, include just one object in the `tools` array.
- If multiple tools are needed, list them sequentially in the `tools` array.
- Always run at least one tool (e.g., `readFile`, `editFile`, `executeCommand`), exept you have finished.
- Always just include one yaml in the response with all the tools you want to run in that yaml.
- Never do write operations on a file which you have not read before. Its contents must be in your context before writing. This does not apply if you create a new file.
- The plugin will verify the `project_name` is correct before running any tools.
- If the response grows too large, I'll guide you to break it into smaller steps.
#### Important Reminders
You are assisting me in a coding workflow for a project (e.g., "my_project").
- **Always** include the `project_name` and the full YAML block with the `tools` array when calling operations.
- **Never** write or modify a file without first having read its content during the current session (unless the file is new).
- **Do not** produce any tool command output that is not strictly formatted as YAML.
1. **Gather Context / Ask Questions**
- If you need more information or something is unclear, **ask me directly** in plain text, without calling any tools.
---
2. **Inspect Files**
- When you need to check a files content, use:
```yaml
project_name: "my_project"
tools:
- tool: "readFile"
path: "relative/path/to/file"
```
- Read the file before deciding on any modifications.
3. **Make Changes**
- If you need to modify an existing file (after reading it), use:
```yaml
project_name: "my_project"
tools:
- tool: "editFile"
path: "relative/path/to/file"
content: |
# Full updated file content
```
- Or perform incremental text replacements with:
```yaml
project_name: "my_project"
tools:
- tool: "replace_in_file"
path: "relative/path/to/file"
replacements:
- search: "old text"
replace: "new text"
```
4. **Run Commands (Optional)**
- To run tests, list files, or do other checks, use:
```yaml
project_name: "my_project"
tools:
- tool: "executeCommand"
command: "shell command here"
```
5. **Important Rules**
- Always start with 1 or 2, but afterwards you can mix 1, 2, 3, and 4 as needed.
- Include `project_name: "my_project"` whenever you call `tools`.
- Keep each tool call in the `tools` array (multiple if needed).
- **Never write to a file you havent read** in this session and already got the content from an response (unless creating a new file).
- Follow secure coding guidelines (input validation, least privilege, no sensitive info in logs, etc.).
- When done, provide a final answer **without** calling any tools.
This revised prompt ensures that during execution the placeholder "%PROJECT_NAME%" is replaced with the actual project name from the current configuration.
]],
["secure-coding"] = [[
### Secure Coding Guidelines

View File

@@ -4,7 +4,7 @@ M.run = function(tool_call, conf, prompt_user_tool_accept, is_subpath, read_file
-- Validate the command exists
local cmd = tool_call.command
if not cmd then
return "[executeCommand] Missing 'command'."
return "[execute_command] Missing 'command'."
end
-- Capture stderr and stdout together by redirecting stderr to stdout
@@ -14,7 +14,7 @@ M.run = function(tool_call, conf, prompt_user_tool_accept, is_subpath, read_file
-- Attempt to popen the command
local handle = io.popen(cmd, "r")
if not handle then
return string.format("Tool [executeCommand '%s'] FAILED to popen.", cmd)
return string.format("Tool [execute_command '%s'] FAILED to popen.", cmd)
end
-- Read the full output (stdout + stderr)
@@ -25,7 +25,7 @@ M.run = function(tool_call, conf, prompt_user_tool_accept, is_subpath, read_file
-- Provide a richer summary including exit code and reason
return string.format(
"Tool [executeCommand '%s'] exited with code %s (%s)\n%s",
"Tool [execute_command '%s'] exited with code %s (%s)\n%s",
cmd,
tostring(exit_code),
tostring(exit_reason),

View File

@@ -8,13 +8,13 @@ local M = {}
-- We can store a table of available tools here
M.available_tools = {
{
name = "readFile",
usage = "Retrieve the contents of a file. Provide { tool='readFile', path='...' }",
name = "read_file",
usage = "Retrieve the contents of a file. Provide { tool='read_file', path='...' }",
explanation = "Use this to read file content directly from the disk."
},
{
name = "editFile",
usage = "Overwrite an entire file's content. Provide { tool='editFile', path='...', content='...' }, Allways include the whole file content",
name = "edit_file",
usage = "Overwrite an entire file's content. Provide { tool='edit_file', path='...', content='...' }, Allways include the whole file content",
explanation = "Use this when you want to replace a file with new content."
},
{
@@ -23,17 +23,17 @@ M.available_tools = {
explanation = "Use this to apply incremental changes without fully overwriting the file."
},
{
name = "executeCommand",
usage = "Run a shell command. Provide { tool='executeCommand', command='...' }",
name = "execute_command",
usage = "Run a shell command. Provide { tool='execute_command', command='...' }",
explanation = "Just run one single command per tool invocation, without comment. It must be a single line. Use with caution, especially for destructive operations (rm, sudo, etc.)."
},
}
M.tools_by_name = {
readFile = read_file_tool,
editFile = edit_file_tool,
read_file = read_file_tool,
edit_file = edit_file_tool,
replace_in_file = replace_in_file_tool,
executeCommand = execute_command_tool
execute_command = execute_command_tool
}
return M

View File

@@ -16,8 +16,8 @@ end
local function prompt_user_tool_accept(tool_call, conf)
local auto_accept = conf.tool_auto_accept[tool_call.tool]
-- If this is an executeCommand and we see it's destructive, force a user prompt
if tool_call.tool == "executeCommand" and auto_accept then
-- If this is an execute_command and we see it's destructive, force a user prompt
if tool_call.tool == "execute_command" and auto_accept then
if is_destructive_command(tool_call.command) then
auto_accept = false
end