Compare commits
2
Commits
e8d7ded32a
...
24aacdfae1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
24aacdfae1 | ||
|
|
b1fc381107 |
No files matched your search
@@ -999,6 +999,31 @@ pub async fn run_mcp_loop(app_name: &str, app_version: &str) {
|
||||
"type": "object",
|
||||
"properties": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "nvim_read_file",
|
||||
"description": "Read specific lines from a file buffer (like cat or sed -n). Reads unsaved changes if open.",
|
||||
"inputSchema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"file": { "type": "string" },
|
||||
"start_line": { "type": "integer", "description": "1-indexed start line (optional, defaults to 1)" },
|
||||
"end_line": { "type": "integer", "description": "1-indexed end line (optional, defaults to end of file)" }
|
||||
},
|
||||
"required": ["file"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "nvim_search_file",
|
||||
"description": "Search for a regex pattern within a file buffer (like grep). Searches unsaved changes if open.",
|
||||
"inputSchema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"file": { "type": "string" },
|
||||
"pattern": { "type": "string", "description": "Lua-compatible regex pattern to search for" }
|
||||
},
|
||||
"required": ["file", "pattern"]
|
||||
}
|
||||
}
|
||||
]
|
||||
})),
|
||||
@@ -1329,6 +1354,72 @@ pub async fn run_mcp_loop(app_name: &str, app_version: &str) {
|
||||
Err(e) => send_error(id, -32603, &e).await,
|
||||
}
|
||||
}
|
||||
|
||||
"nvim_read_file" => {
|
||||
if let Some(file) = args.get("file").and_then(|v| v.as_str()) {
|
||||
let start_line = args.get("start_line").and_then(|v| v.as_i64()).unwrap_or(1);
|
||||
let end_line = args.get("end_line").and_then(|v| v.as_i64()).unwrap_or(-1);
|
||||
|
||||
let escaped_file = file.replace('\\', "\\\\").replace('"', "\\\"");
|
||||
let code = format!("
|
||||
local file = \"{escaped_file}\"
|
||||
local start_idx = {start_line} - 1
|
||||
local end_idx = {end_line}
|
||||
local bufnr = vim.fn.bufnr(file, true)
|
||||
if vim.fn.bufloaded(bufnr) == 0 then
|
||||
vim.fn.bufload(bufnr)
|
||||
end
|
||||
local lines = vim.api.nvim_buf_get_lines(bufnr, start_idx, end_idx, false)
|
||||
local res = {{}}
|
||||
for i, line in ipairs(lines) do
|
||||
local line_num = start_idx + i
|
||||
table.insert(res, tostring(line_num) .. ': ' .. line)
|
||||
end
|
||||
return table.concat(res, '\\n')
|
||||
");
|
||||
match execute_nvim_lua(&code).await {
|
||||
Ok(res) => send_text_result!(id.clone(), res),
|
||||
Err(e) => send_error(id, -32603, &e).await,
|
||||
}
|
||||
} else {
|
||||
send_error(id, -32602, "Missing 'file'").await;
|
||||
}
|
||||
}
|
||||
|
||||
"nvim_search_file" => {
|
||||
if let (Some(file), Some(pattern)) = (
|
||||
args.get("file").and_then(|v| v.as_str()),
|
||||
args.get("pattern").and_then(|v| v.as_str()),
|
||||
) {
|
||||
let escaped_file = file.replace('\\', "\\\\").replace('"', "\\\"");
|
||||
let escaped_pattern = pattern.replace('\\', "\\\\").replace('"', "\\\"");
|
||||
let code = format!("
|
||||
local file = \"{escaped_file}\"
|
||||
local pattern = \"{escaped_pattern}\"
|
||||
local bufnr = vim.fn.bufnr(file, true)
|
||||
if vim.fn.bufloaded(bufnr) == 0 then
|
||||
vim.fn.bufload(bufnr)
|
||||
end
|
||||
local lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, false)
|
||||
local matches = {{}}
|
||||
for i, line in ipairs(lines) do
|
||||
if string.match(line, pattern) then
|
||||
table.insert(matches, tostring(i) .. ': ' .. line)
|
||||
end
|
||||
end
|
||||
if #matches == 0 then
|
||||
return 'No matches found.'
|
||||
end
|
||||
return table.concat(matches, '\\n')
|
||||
");
|
||||
match execute_nvim_lua(&code).await {
|
||||
Ok(res) => send_text_result!(id.clone(), res),
|
||||
Err(e) => send_error(id, -32603, &e).await,
|
||||
}
|
||||
} else {
|
||||
send_error(id, -32602, "Missing 'file' or 'pattern'").await;
|
||||
}
|
||||
}
|
||||
|
||||
"nvim_execute_lua" => {
|
||||
if let Some(code) = args.get("code").and_then(|v| v.as_str()) {
|
||||
|
||||
@@ -631,7 +631,7 @@ mod tests {
|
||||
let create_handler = CreateEntitiesHandler;
|
||||
let args = json!({
|
||||
"entities": [
|
||||
{"name": "Alice", "entityType": "Person", "observations": ["Likes Bob"]}
|
||||
{"name": "Alice", "entity_type": "Person", "observations": ["Likes Bob"]}
|
||||
]
|
||||
});
|
||||
|
||||
@@ -677,7 +677,7 @@ mod tests {
|
||||
let handler = CreateRelationsHandler;
|
||||
let args = json!({
|
||||
"relations": [
|
||||
{"from": "A", "to": "B", "relationType": "knows"}
|
||||
{"from": "A", "to": "B", "relation_type": "knows"}
|
||||
]
|
||||
});
|
||||
let res = handler.execute(args, state.clone()).await.unwrap();
|
||||
@@ -706,7 +706,7 @@ mod tests {
|
||||
let add_obs = AddObservationsHandler;
|
||||
let args_obs = json!({
|
||||
"observations": [
|
||||
{"entityName": "A", "contents": ["Obs 1", "Obs 2"]}
|
||||
{"entity_name": "A", "contents": ["Obs 1", "Obs 2"]}
|
||||
]
|
||||
});
|
||||
let res1 = add_obs.execute(args_obs, state.clone()).await.unwrap();
|
||||
@@ -722,7 +722,7 @@ mod tests {
|
||||
|
||||
let del_entity = DeleteEntitiesHandler;
|
||||
let res4 = del_entity
|
||||
.execute(json!({"entityNames": ["A"]}), state.clone())
|
||||
.execute(json!({"entity_names": ["A"]}), state.clone())
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(res4, "Entities deleted");
|
||||
@@ -742,8 +742,8 @@ mod tests {
|
||||
let create_handler = CreateEntitiesHandler;
|
||||
let args_ent = json!({
|
||||
"entities": [
|
||||
{"name": "X", "entityType": "File", "observations": ["Obs X"], "namespace": "global"},
|
||||
{"name": "Y", "entityType": "File", "observations": ["Obs Y"], "namespace": "global"}
|
||||
{"name": "X", "entity_type": "File", "observations": ["Obs X"], "namespace": "global"},
|
||||
{"name": "Y", "entity_type": "File", "observations": ["Obs Y"], "namespace": "global"}
|
||||
]
|
||||
});
|
||||
create_handler
|
||||
@@ -754,7 +754,7 @@ mod tests {
|
||||
let rel_handler = CreateRelationsHandler;
|
||||
let args_rel = json!({
|
||||
"relations": [
|
||||
{"from": "X", "to": "Y", "relationType": "depends_on", "namespace": "global"}
|
||||
{"from": "X", "to": "Y", "relation_type": "depends_on", "namespace": "global"}
|
||||
]
|
||||
});
|
||||
rel_handler.execute(args_rel, state.clone()).await.unwrap();
|
||||
@@ -784,7 +784,7 @@ mod tests {
|
||||
let condense = CondenseEntityHandler;
|
||||
let res_cond = condense
|
||||
.execute(
|
||||
json!({"entityName": "X", "summarized_observations": ["X condensed"]}),
|
||||
json!({"entity_name": "X", "summarized_observations": ["X condensed"]}),
|
||||
state.clone(),
|
||||
)
|
||||
.await
|
||||
@@ -794,7 +794,7 @@ mod tests {
|
||||
let merge = MergeEntitiesHandler;
|
||||
let res_merge = merge
|
||||
.execute(
|
||||
json!({"sourceEntity": "X", "targetEntity": "Y"}),
|
||||
json!({"source_entity": "X", "target_entity": "Y"}),
|
||||
state.clone(),
|
||||
)
|
||||
.await
|
||||
|
||||
@@ -609,7 +609,7 @@ mod tests {
|
||||
|
||||
let code_handler = LogCodeChangeHandler;
|
||||
let args_code = json!({
|
||||
"filePath": "main.rs",
|
||||
"file_path": "main.rs",
|
||||
"description": "refactor",
|
||||
"git_commit": "def",
|
||||
"git_branch": "main"
|
||||
|
||||
Reference in new issue
Block a user