370 lines
17 KiB
Lua
370 lines
17 KiB
Lua
require('helpers').edit_cf('pa', '/lua/plugins/codecompanion.lua')
|
||
|
||
vim.cmd [[cab cc CodeCompanion]]
|
||
|
||
return {
|
||
'olimorris/codecompanion.nvim',
|
||
opts = function(_, opts)
|
||
opts.adapters = {
|
||
gpt = function()
|
||
return require('codecompanion.adapters').extend('copilot', {
|
||
schema = {
|
||
model = {
|
||
default = 'gpt-4.1',
|
||
},
|
||
max_tokens = {
|
||
default = 1000000,
|
||
},
|
||
},
|
||
})
|
||
end,
|
||
flash = function()
|
||
return require('codecompanion.adapters').extend('copilot', {
|
||
schema = {
|
||
model = {
|
||
default = 'gemini-2.0-flash-001',
|
||
},
|
||
max_tokens = {
|
||
default = 1000000,
|
||
},
|
||
},
|
||
})
|
||
end,
|
||
gemini = function()
|
||
return require('codecompanion.adapters').extend('copilot', {
|
||
schema = {
|
||
model = {
|
||
default = 'gemini-2.5-pro',
|
||
},
|
||
max_tokens = {
|
||
default = 1000000,
|
||
},
|
||
},
|
||
})
|
||
end,
|
||
sonnet = function()
|
||
return require('codecompanion.adapters').extend('copilot', {
|
||
schema = {
|
||
model = {
|
||
default = 'claude-3.7-sonnet',
|
||
},
|
||
max_tokens = {
|
||
default = 1000000,
|
||
},
|
||
},
|
||
})
|
||
end,
|
||
}
|
||
|
||
opts.display = {
|
||
chat = {
|
||
show_settings = true,
|
||
start_in_insert_mode = false,
|
||
},
|
||
}
|
||
|
||
opts.strategies = {
|
||
chat = {
|
||
adapter = 'gpt',
|
||
slash_commands = {
|
||
codebase = require('vectorcode.integrations').codecompanion.chat.make_slash_command(),
|
||
},
|
||
tools = {
|
||
vectorcode = {
|
||
description = 'Run VectorCode to retrieve the project context.',
|
||
callback = require('vectorcode.integrations').codecompanion.chat.make_tool(),
|
||
},
|
||
['cmd_runner'] = {
|
||
opts = {
|
||
requires_approval = false,
|
||
},
|
||
},
|
||
},
|
||
roles = {
|
||
---@type string|fun(adapter: CodeCompanion.Adapter): string
|
||
llm = function(adapter)
|
||
return 'CodeCompanion (' .. adapter.formatted_name .. ': ' .. adapter.parameters.model .. ')'
|
||
end,
|
||
},
|
||
keymaps = {
|
||
send = {
|
||
modes = { n = '<C-s>', i = '<C-s>' },
|
||
},
|
||
close = {
|
||
modes = { n = '<C-c>', i = '<C-c>' },
|
||
},
|
||
},
|
||
},
|
||
inline = {
|
||
adapter = 'flash',
|
||
},
|
||
}
|
||
|
||
opts.extensions = {
|
||
mcphub = {
|
||
callback = 'mcphub.extensions.codecompanion',
|
||
opts = {
|
||
show_result_in_chat = true,
|
||
make_vars = true,
|
||
make_slash_commands = true,
|
||
},
|
||
},
|
||
}
|
||
|
||
opts.system_prompt = function(opts)
|
||
local language = opts.language or 'English'
|
||
return string.format(
|
||
[[You are an AI programming assistant named "CodeCompanion". You are currently plugged into the Neovim text editor on a user's machine.
|
||
|
||
Your core tasks include:
|
||
- Answering general programming questions.
|
||
- Explaining how the code in a Neovim buffer works.
|
||
- Reviewing the selected code from a Neovim buffer.
|
||
- Generating unit tests for the selected code.
|
||
- Proposing fixes for problems in the selected code.
|
||
- Scaffolding code for a new workspace.
|
||
- Finding relevant code to the user's query.
|
||
- Proposing fixes for test failures.
|
||
- Answering questions about Neovim.
|
||
- Running tools.
|
||
|
||
You must:
|
||
- Follow the user's requirements carefully and to the letter.
|
||
- Keep your answers short and impersonal, especially if the user's context is outside your core tasks.
|
||
- Minimize additional prose unless clarification is needed.
|
||
- Use Markdown formatting in your answers.
|
||
- Include the programming language name at the start of each Markdown code block.
|
||
- Avoid including line numbers in code blocks.
|
||
- Avoid wrapping the whole response in triple backticks.
|
||
- Only return code that's directly relevant to the task at hand. You may omit code that isn’t necessary for the solution.
|
||
- Avoid using H1, H2 or H3 headers in your responses as these are reserved for the user.
|
||
- Use actual line breaks in your responses; only use "\n" when you want a literal backslash followed by 'n'.
|
||
- All non-code text responses must be written in the %s language indicated.
|
||
- Multiple, different tools can be called as part of the same response.
|
||
- Use full path names when using tools to read and modify files.
|
||
|
||
When given a task:
|
||
1. Think step-by-step and, unless the user requests otherwise or the task is very simple, describe your plan in detailed pseudocode.
|
||
2. Output the final code in a single code block, ensuring that only relevant code is included.
|
||
3. End your response with a short suggestion for the next user turn that directly supports continuing the conversation.
|
||
4. Provide exactly one complete reply per conversation turn.
|
||
5. If necessary, execute multiple tools in a single turn.]],
|
||
language
|
||
)
|
||
end
|
||
|
||
opts.prompt_library = {
|
||
['Code Expert'] = {
|
||
strategy = 'chat',
|
||
description = 'Get some special adcvice from an LLM.',
|
||
opts = {
|
||
mapping = '<Leader>ce',
|
||
modes = { 'v' },
|
||
short_name = 'expert',
|
||
auto_submit = true,
|
||
stop_context_insertion = true,
|
||
user_prompt = true,
|
||
},
|
||
prompts = {
|
||
{
|
||
role = 'system',
|
||
content = function(context)
|
||
return 'I want you to act as a senior'
|
||
.. context.filetype
|
||
.. 'developer I will ask you specific questions and I want you to return concise explanations and codeblock examples.'
|
||
end,
|
||
},
|
||
{
|
||
role = 'user',
|
||
content = function(context)
|
||
local text = require('codecompanion.helpers.actions').get_code(context.start_line, context.end_line)
|
||
|
||
return 'I have the following code:\n\n```' .. context.filetype .. '\n' .. text .. '\n```\n\n'
|
||
end,
|
||
opts = {
|
||
contains_code = true,
|
||
},
|
||
},
|
||
},
|
||
},
|
||
['Games Master'] = {
|
||
strategy = 'chat',
|
||
description = 'A personal Games Master Assistant.',
|
||
opts = {
|
||
mapping = '<Leader>cd',
|
||
modes = { 'n' },
|
||
short_name = 'gm',
|
||
auto_submit = false,
|
||
stop_context_insertion = false,
|
||
user_prompt = false,
|
||
is_default = true,
|
||
adapter = {
|
||
temperature = 1,
|
||
},
|
||
},
|
||
prompts = {
|
||
{
|
||
role = 'system',
|
||
content = function(context)
|
||
return [[
|
||
You are a personal Games Master Assistant. You are currently plugged in to the Neovim text editor on a user's machine.
|
||
|
||
Your core tasks include:
|
||
- Crafting engaging role playing sessions
|
||
- Building immersive and authentic worlds
|
||
- Creating compelling characters for the players to interact with and drive the story
|
||
- Reviewing session summaries and building on them
|
||
- Providing advice on how to bring sessions to life
|
||
- Create exciting encounters to challenge the players
|
||
- Encounters can be combat, social, or exploration based
|
||
- There should always be a story reason for the encounter
|
||
- Combine player character backgrounds and motivations into the world
|
||
- Build tension and drama into the game
|
||
- Ensure each session provides opportunities for the players to engage with and drive the story
|
||
|
||
You must:
|
||
- Follow the user's requirements carefully and to the letter.
|
||
- Keep answers focused on the task at hand.
|
||
- Provide original ideas and suggestions.
|
||
- Use Markdown formatting in your answers.
|
||
- Use actual line breaks instead of '\n' in your response to begin new lines.
|
||
- Use '\n' only when you want a literal backslash followed by a character 'n'.
|
||
- All responses must be written in English.
|
||
- Multiple, different tools can be called as part of the same response.
|
||
- Help sessions be fast paced and fun.
|
||
- Ensure there are multiple soltuions to each problem.
|
||
- Avoid railroading the players.
|
||
|
||
When given a task:
|
||
1. Consider the existing world and characters. Use tools to gather information that may be relevant.
|
||
2. Provide exactly one complete reply per conversation turn.
|
||
3. If necessary, execute multiple tools in a single turn.
|
||
]]
|
||
end,
|
||
},
|
||
{
|
||
role = 'user',
|
||
content = function(context)
|
||
return ''
|
||
end,
|
||
opts = {
|
||
contains_code = false,
|
||
},
|
||
},
|
||
},
|
||
},
|
||
['PHPStan Fixer'] = {
|
||
strategy = 'workflow',
|
||
description = 'Use a workflow to fix PHPStan errors until there are none left.',
|
||
opts = {
|
||
short_name = 'phpstan',
|
||
},
|
||
prompts = {
|
||
{
|
||
{
|
||
name = 'Run PHPStan',
|
||
role = 'user',
|
||
opts = { auto_submit = false },
|
||
content = function()
|
||
-- Enable turbo mode!!!
|
||
vim.g.codecompanion_auto_tool_mode = true
|
||
|
||
return [[PHPStan is a static analysis tool for PHP. It is currently reporting errors in the code. Your task is to fix these errors and run PHPStan again until there are no errors left.
|
||
|
||
First of all use the @cmd_runner tool to run the `composer type-check` command. This will run PHPStan and output type errors in the code.]]
|
||
end,
|
||
},
|
||
},
|
||
{
|
||
{
|
||
name = 'Fetch files',
|
||
role = 'user',
|
||
opts = { auto_submit = false },
|
||
content = function()
|
||
-- Enable turbo mode!!!
|
||
vim.g.codecompanion_auto_tool_mode = true
|
||
|
||
return 'PHPStan has reported errors. Look at the output and see where the files are reported. Use the @mcp tool to read all the offending files so you can implement the fixes.'
|
||
end,
|
||
},
|
||
},
|
||
{
|
||
{
|
||
name = 'Fix errors and run',
|
||
role = 'user',
|
||
opts = { auto_submit = false },
|
||
content = function()
|
||
-- Enable turbo mode!!!
|
||
vim.g.codecompanion_auto_tool_mode = true
|
||
|
||
return [[### Instructions
|
||
Now you have the errors and the appropriate context you can fix the errors.
|
||
|
||
### Steps to Follow
|
||
|
||
You are required to analyse the PHPStan errors and write code to fix them.
|
||
|
||
Reason through the errors and write out the possible causes and fixes for each.
|
||
|
||
1. Then use the @mcp tool to update the files with the fixes. When editing files use the full path name including the project name /Users/chris/Code/Sites/hylark/
|
||
2. After editing the files use the @cmd_runner tool again to run the `composer type-check` command to see if any errors remain.
|
||
|
||
We'll repeat this cycle until there are no errors. Ensure no deviations from these steps.
|
||
|
||
### Tips for fixing PHPStan errors
|
||
- Do not ignore the errors
|
||
- Use Webmozart Assert library to narrow types
|
||
- Most errors are due to missing docblocks or calling methods/parameters on types that PHPStan cannot infer
|
||
- Use fully qualified namespaces for classes in doc blocks
|
||
- The code is working so fixes should not change the behaviour of the code
|
||
- There are some custom types in this project that help define types
|
||
- closure<T> creates T|Closure(): T, you can add a second argument to specify the depth so closure<T, 2> creates T|Closure(): T|Closure(): (Closure(): T). This is useful because GraphQL queries can return closures.
|
||
- promise<T> creates T|SyncPromise<T>, as with closure, you can add a second argument for depth. You can also add a third argument if T is an array to allow adding promises to each value, so promise<array{a: int}, 1, 1> will create array{a: int}|SyncPromise<array{a: int}>|array{a: SyncPromise<int>}|SyncPromise<array{a: SyncPromise<int>}>. This is useful because GraphQL queries can return promises and arrays of promises.
|
||
- GraphQL schema types (these should only be used in the Query classes)
|
||
- GArgs<T> will look at the GraphQL schema and create an array type for the arguments of a field on one of the root types (Query or Mutation)
|
||
- GArgs<TType, TField> will create a type for the arguments of a field on a type
|
||
- GType<T> will create an type for a specific GraphQL type, input, interface, or enum
|
||
- GVal<T> will create a type for the return value of a field on one of the root types (Query or Mutation)
|
||
- GVal<TType, TField> will create a type for the return value of a field on a type
|
||
- pick<T, TKeys> will create an array from T with only the keys in TKeys (e.g. pick<array{a: int, b: int, c: int}, 'a'|'b'> will create array{a: int, b: int})
|
||
- except<T, TKeys> works like pick only it excludes the keys in TKeys (e.g. except<array{a: int, b: int, c: int}, 'a'|'b'> will create array{c: int})
|
||
- union<T, U> creates a union array of T and U (e.g. union<array{a: int}, array{b: int}> will create array{a: int, b: int})]]
|
||
end,
|
||
},
|
||
},
|
||
{
|
||
{
|
||
name = 'Repeat On Failure',
|
||
role = 'user',
|
||
opts = { auto_submit = false },
|
||
-- Scope this prompt to the cmd_runner tool
|
||
condition = function()
|
||
return _G.codecompanion_current_tool == 'cmd_runner'
|
||
end,
|
||
-- Repeat until the tests pass, as indicated by the testing flag
|
||
-- which the cmd_runner tool sets on the chat buffer
|
||
repeat_until = function(chat)
|
||
-- Check if the last message in the chat buffer contains "[ERROR] found"
|
||
local messages = chat.messages
|
||
local last_message = messages[#messages]
|
||
if last_message and last_message.role == 'assistant' then
|
||
local content = last_message.content
|
||
return not content:find '[ERROR] found'
|
||
end
|
||
return true
|
||
end,
|
||
content = 'PHPStan is still reporting errors. Edit the code to fix the errors and run PHPStan again.',
|
||
},
|
||
},
|
||
},
|
||
},
|
||
}
|
||
end,
|
||
dependencies = {
|
||
'nvim-lua/plenary.nvim',
|
||
'nvim-treesitter/nvim-treesitter',
|
||
'Davidyz/VectorCode',
|
||
'ravitemer/mcphub.nvim',
|
||
},
|
||
}
|