Compare commits
18 Commits
4d679e43cb
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 7fb8671840 | |||
| 32fcc2622f | |||
| a5bad60d8e | |||
| 1deae056b7 | |||
| 07eceb4bee | |||
| 216a4f2603 | |||
| 0617f5ba5b | |||
| 51f7c2c66f | |||
| 5b972c5c9f | |||
| 01932be82a | |||
| e5f4558df5 | |||
| 0f044a625e | |||
| ebc0791542 | |||
| 9d72ba46c4 | |||
| 2b9aa5f35f | |||
| bf04d2f2fc | |||
| d9a1cf83fc | |||
| d19451ca5c |
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,7 +148,9 @@ function M.get_project_files(directories, conf)
|
||||
local rel_files = {}
|
||||
for _, f in ipairs(all_files) do
|
||||
local rel = vim.fn.fnamemodify(f, ":.")
|
||||
table.insert(rel_files, rel)
|
||||
if not rel:match("^%.?chatgpt_config%.yaml$") then
|
||||
table.insert(rel_files, rel)
|
||||
end
|
||||
end
|
||||
|
||||
if conf.debug then
|
||||
@@ -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
|
||||
return structure .. "\n" .. contents
|
||||
else
|
||||
return structure
|
||||
end
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
@@ -44,7 +121,7 @@ local M = {
|
||||
5. **Styling & CSS Management**
|
||||
- Use your preferred styling approach (CSS Modules, [Tailwind CSS](https://tailwindcss.com/), or standard CSS/SCSS files).
|
||||
- Keep global styles minimal, focusing on utility classes or base styling; keep component-level styles scoped whenever possible.
|
||||
- If using CSS-in-JS solutions or third-party libraries, ensure they integrate cleanly with Solid’s reactivity.
|
||||
- If using CSS-in-JS solutions or third-party libraries, ensure they integrate cleanly with Solid’s reactivity.
|
||||
|
||||
6. **TypeScript & Linting**
|
||||
- Use **TypeScript** to ensure type safety and improve maintainability.
|
||||
@@ -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,22 +238,23 @@ 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 module’s structure (e.g., `moduleName/internal/packageA`).
|
||||
- If you refer to internal packages, use relative paths consistent with the module’s 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.
|
||||
- Avoid creating multiple packages in the same folder.
|
||||
- Use descriptive folder names and keep package names concise, following Go naming conventions.
|
||||
- Do not duplicate function or type names across different files in the same folder/package.
|
||||
- Do not duplicate function or type names across different files in the same folder/package.
|
||||
|
||||
3. **File & Folder Organization**
|
||||
- Organize source code in a folder hierarchy that reflects functionality. For example:
|
||||
@@ -194,28 +272,26 @@ local M = {
|
||||
└── shared/
|
||||
```
|
||||
- Keep external-facing, reusable packages in `pkg/` and internal logic in `internal/`.
|
||||
- Place the `main()` function in the `cmd/<appname>` folder.
|
||||
- Place the `main()` function in the `cmd/<appname>` folder.
|
||||
|
||||
4. **Coding Best Practices**
|
||||
- Maintain idiomatic Go code (e.g., short function and variable names where obvious, PascalCase for exported symbols).
|
||||
- Keep functions short, focused, and tested.
|
||||
- Use Go’s standard library where possible before adding third-party dependencies.
|
||||
- When introducing new functions or types, ensure they are uniquely named to avoid collisions.
|
||||
- Use Go’s standard library where possible before adding third-party dependencies.
|
||||
- When introducing new functions or types, ensure they are uniquely named to avoid collisions.
|
||||
|
||||
5. **Import Management**
|
||||
- Ensure that every import is actually used in your code.
|
||||
- Remove unused imports to keep your code clean and maintainable.
|
||||
- Include all necessary imports for anything referenced in your code to avoid missing imports.
|
||||
- Verify that any introduced import paths match your module’s structure and do not cause naming conflicts.
|
||||
- Verify that any introduced import paths match your module’s structure and do not cause naming conflicts.
|
||||
|
||||
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 Golang’s 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:
|
||||
@@ -239,10 +315,10 @@ local M = {
|
||||
- Keep site configuration in `config/sites/` (for TYPO3 v9+).
|
||||
|
||||
2. **Extension Development**
|
||||
- Create custom functionality as separate extensions (site packages, domain-specific extensions, etc.) following TYPO3’s recommended structure:
|
||||
- Create custom functionality as separate extensions (site packages, domain-specific extensions, etc.) following TYPO3’s recommended structure:
|
||||
- **Key files**: `ext_emconf.php`, `ext_localconf.php`, `ext_tables.php`, `ext_tables.sql`, `Configuration/`, `Classes/`, `Resources/`.
|
||||
- Use **PSR-4** autoloading and name extensions logically (e.g., `my_sitepackage`, `my_blogextension`).
|
||||
- Keep your extension’s code under `Classes/` (e.g., Controllers, Models, Services).
|
||||
- Keep your extension’s code under `Classes/` (e.g., Controllers, Models, Services).
|
||||
- Place Fluid templates, partials, and layouts under `Resources/Private/` (e.g., `Resources/Private/Templates`, `Resources/Private/Partials`, `Resources/Private/Layouts`).
|
||||
|
||||
3. **Configuration (TypoScript & TCA)**
|
||||
@@ -275,12 +351,10 @@ local M = {
|
||||
7. **Output Format**
|
||||
- Present any generated source code or configuration files in a well-organized structure.
|
||||
- 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 site’s main configuration.”).
|
||||
- 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 site’s 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 TYPO3’s 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:
|
||||
@@ -293,11 +367,11 @@ local M = {
|
||||
2. **Crates & Packages**
|
||||
- Split the application into logical crates (libraries and/or binaries).
|
||||
- Each crate should have a single main **library** (`lib.rs`) or **binary** (`main.rs`) in its `src/` folder.
|
||||
- Name crates, modules, and files clearly, following Rust’s naming conventions (e.g., `snake_case` for files/modules, `PascalCase` for types).
|
||||
- Name crates, modules, and files clearly, following Rust’s naming conventions (e.g., `snake_case` for files/modules, `PascalCase` for types).
|
||||
- Avoid duplicating the same function or type in multiple crates; share common functionality via a dedicated library crate if needed.
|
||||
|
||||
3. **Folder & Module Structure**
|
||||
- Organize code within each crate using Rust’s module system, keeping related functions and types in logical modules/submodules.
|
||||
- Organize code within each crate using Rust’s module system, keeping related functions and types in logical modules/submodules.
|
||||
- A typical directory layout for a workspace with multiple crates might look like:
|
||||
```
|
||||
myproject/
|
||||
@@ -315,19 +389,19 @@ local M = {
|
||||
├── target/
|
||||
└── ...
|
||||
```
|
||||
- If you have integration tests, store them in a `tests/` folder at the crate root, or use the workspace root’s `tests/` directory if they span multiple crates.
|
||||
- If you have integration tests, store them in a `tests/` folder at the crate root, or use the workspace root’s `tests/` directory if they span multiple crates.
|
||||
|
||||
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,77 +413,57 @@ 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):
|
||||
```yaml
|
||||
project_name: "my_project"
|
||||
tools:
|
||||
- tool: "readFile"
|
||||
path: "relative/path/to/file"
|
||||
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.**
|
||||
|
||||
- tool: "replace_in_file"
|
||||
path: "relative/path/to/file"
|
||||
replacements:
|
||||
- search: "old text"
|
||||
replace: "new text"
|
||||
|
||||
- tool: "editFile"
|
||||
path: "relative/path/to/file"
|
||||
content: |
|
||||
# Full updated file content here
|
||||
|
||||
- tool: "executeCommand"
|
||||
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.
|
||||
|
||||
You are assisting me in a coding workflow for a project (e.g., "my_project").
|
||||
|
||||
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 file’s content, use:
|
||||
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 file’s contents, always use the following YAML format:
|
||||
```yaml
|
||||
project_name: "%PROJECT_NAME%"
|
||||
tools:
|
||||
- tool: "readFile"
|
||||
- tool: "read_file"
|
||||
path: "relative/path/to/file"
|
||||
```
|
||||
- Read the file before deciding on any modifications.
|
||||
- Use the information from this operation to decide if and how to modify the file.
|
||||
|
||||
3. **Make Changes**
|
||||
- If you need to modify an existing file (after reading it), use:
|
||||
6. **Modifying Files**
|
||||
- To modify a file that you have already read, use:
|
||||
```yaml
|
||||
project_name: "my_project"
|
||||
project_name: "%PROJECT_NAME%"
|
||||
tools:
|
||||
- tool: "editFile"
|
||||
- tool: "edit_file"
|
||||
path: "relative/path/to/file"
|
||||
content: |
|
||||
# Full updated file content
|
||||
# Full updated file content here
|
||||
```
|
||||
- Or perform incremental text replacements with:
|
||||
- Alternatively, for incremental changes, use:
|
||||
```yaml
|
||||
project_name: "my_project"
|
||||
project_name: "%PROJECT_NAME%"
|
||||
tools:
|
||||
- tool: "replace_in_file"
|
||||
path: "relative/path/to/file"
|
||||
@@ -418,22 +472,62 @@ local M = {
|
||||
replace: "new text"
|
||||
```
|
||||
|
||||
4. **Run Commands (Optional)**
|
||||
- To run tests, list files, or do other checks, use:
|
||||
7. **Executing Commands**
|
||||
- To run any shell command (e.g., testing, listing files), use:
|
||||
```yaml
|
||||
project_name: "my_project"
|
||||
project_name: "%PROJECT_NAME%"
|
||||
tools:
|
||||
- tool: "executeCommand"
|
||||
- tool: "execute_command"
|
||||
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 haven’t 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.
|
||||
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"
|
||||
path: "relative/path/to/file"
|
||||
replacements:
|
||||
- search: "old text"
|
||||
replace: "new text"
|
||||
|
||||
- tool: "edit_file"
|
||||
path: "relative/path/to/file"
|
||||
content: |
|
||||
# Full updated file content here
|
||||
|
||||
- tool: "execute_command"
|
||||
command: "ls -la"
|
||||
```
|
||||
|
||||
#### Important Reminders
|
||||
|
||||
- **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.
|
||||
|
||||
---
|
||||
|
||||
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
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user