tool/lsp: include request details in permission metadata

The lsp tool asks for permission without attaching enough context for
permission UIs to explain what is about to run.

Include the operation, path and cursor position in the permission metadata so
prompts can describe the request before execution. Also make the execute
wrapper match the other tool implementations.
This commit is contained in:
Simon Klee
2026-04-24 12:11:32 +02:00
parent f8e939d96f
commit 7510888aba
2 changed files with 182 additions and 4 deletions
+20 -4
View File
@@ -36,7 +36,6 @@ export const LspTool = Tool.define(
Effect.gen(function* () {
const lsp = yield* LSP.Service
const fs = yield* AppFileSystem.Service
return {
description: DESCRIPTION,
parameters: Parameters,
@@ -47,12 +46,29 @@ export const LspTool = Tool.define(
Effect.gen(function* () {
const file = path.isAbsolute(args.filePath) ? args.filePath : path.join(Instance.directory, args.filePath)
yield* assertExternalDirectoryEffect(ctx, file)
yield* ctx.ask({ permission: "lsp", patterns: ["*"], always: ["*"], metadata: {} })
const meta =
args.operation === "workspaceSymbol"
? { operation: args.operation }
: args.operation === "documentSymbol"
? { operation: args.operation, filePath: file }
: { operation: args.operation, filePath: file, line: args.line, character: args.character }
yield* ctx.ask({
permission: "lsp",
patterns: ["*"],
always: ["*"],
metadata: meta,
})
const uri = pathToFileURL(file).href
const position = { file, line: args.line - 1, character: args.character - 1 }
const relPath = path.relative(Instance.worktree, file)
const title = `${args.operation} ${relPath}:${args.line}:${args.character}`
const detail =
args.operation === "workspaceSymbol"
? ""
: args.operation === "documentSymbol"
? relPath
: `${relPath}:${args.line}:${args.character}`
const title = detail ? `${args.operation} ${detail}` : args.operation
const exists = yield* fs.existsSafe(file)
if (!exists) throw new Error(`File not found: ${file}`)
@@ -90,7 +106,7 @@ export const LspTool = Tool.define(
metadata: { result },
output: result.length === 0 ? `No results found for ${args.operation}` : JSON.stringify(result, null, 2),
}
}),
}).pipe(Effect.orDie),
}
}),
)