UNPKG

pyb-ts

Version:

PYB-CLI - Minimal AI Agent with multi-model support and CLI interface

195 lines (194 loc) 6.28 kB
import { BashTool, inputSchema } from "./tools/BashTool/BashTool.js"; import { FileEditTool } from "./tools/FileEditTool/FileEditTool.js"; import { FileWriteTool } from "./tools/FileWriteTool/FileWriteTool.js"; import { NotebookEditTool } from "./tools/NotebookEditTool/NotebookEditTool.js"; import { getCommandSubcommandPrefix, splitCommand } from "./utils/commands.js"; import { getCurrentProjectConfig, saveCurrentProjectConfig } from "@utils/config"; import { AbortError } from "./utils/errors.js"; import { logError } from "./utils/log.js"; import { grantWritePermissionForOriginalDir } from "./utils/permissions/filesystem.js"; import { getCwd } from "./utils/state.js"; import { PRODUCT_NAME } from "./constants/product.js"; const SAFE_COMMANDS = /* @__PURE__ */ new Set([ "git status", "git diff", "git log", "git branch", "pwd", "tree", "date", "which" ]); const bashToolCommandHasExactMatchPermission = (tool, command, allowedTools) => { if (SAFE_COMMANDS.has(command)) { return true; } if (allowedTools.includes(getPermissionKey(tool, { command }, null))) { return true; } if (allowedTools.includes(getPermissionKey(tool, { command }, command))) { return true; } return false; }; const bashToolCommandHasPermission = (tool, command, prefix, allowedTools) => { if (bashToolCommandHasExactMatchPermission(tool, command, allowedTools)) { return true; } return allowedTools.includes(getPermissionKey(tool, { command }, prefix)); }; const bashToolHasPermission = async (tool, command, context, allowedTools, getCommandSubcommandPrefixFn = getCommandSubcommandPrefix) => { if (bashToolCommandHasExactMatchPermission(tool, command, allowedTools)) { return { result: true }; } const subCommands = splitCommand(command).filter((_) => { if (_ === `cd ${getCwd()}`) { return false; } return true; }); const commandSubcommandPrefix = await getCommandSubcommandPrefixFn( command, context.abortController.signal ); if (context.abortController.signal.aborted) { throw new AbortError(); } if (commandSubcommandPrefix === null) { return { result: false, message: `${PRODUCT_NAME} requested permissions to use ${tool.name}, but you haven't granted it yet.` }; } if (commandSubcommandPrefix.commandInjectionDetected) { if (bashToolCommandHasExactMatchPermission(tool, command, allowedTools)) { return { result: true }; } else { return { result: false, message: `${PRODUCT_NAME} requested permissions to use ${tool.name}, but you haven't granted it yet.` }; } } if (subCommands.length < 2) { if (bashToolCommandHasPermission( tool, command, commandSubcommandPrefix.commandPrefix, allowedTools )) { return { result: true }; } else { return { result: false, message: `${PRODUCT_NAME} requested permissions to use ${tool.name}, but you haven't granted it yet.` }; } } if (subCommands.every((subCommand) => { const prefixResult = commandSubcommandPrefix.subcommandPrefixes.get(subCommand); if (prefixResult === void 0 || prefixResult.commandInjectionDetected) { return false; } const hasPermission = bashToolCommandHasPermission( tool, subCommand, prefixResult ? prefixResult.commandPrefix : null, allowedTools ); return hasPermission; })) { return { result: true }; } return { result: false, message: `${PRODUCT_NAME} requested permissions to use ${tool.name}, but you haven't granted it yet.` }; }; const hasPermissionsToUseTool = async (tool, input, context, _assistantMessage) => { if (!context.options.safeMode) { return { result: true }; } if (context.abortController.signal.aborted) { throw new AbortError(); } try { if (!tool.needsPermissions(input)) { return { result: true }; } } catch (e) { logError(`Error checking permissions: ${e}`); return { result: false, message: "Error checking permissions" }; } const projectConfig = getCurrentProjectConfig(); const allowedTools = projectConfig.allowedTools ?? []; if (tool === BashTool && allowedTools.includes(BashTool.name)) { return { result: true }; } switch (tool) { // For bash tool, check each sub-command's permissions separately case BashTool: { const { command } = inputSchema.parse(input); return await bashToolHasPermission(tool, command, context, allowedTools); } // For file editing tools, check session-only permissions case FileEditTool: case FileWriteTool: case NotebookEditTool: { if (!tool.needsPermissions(input)) { return { result: true }; } return { result: false, message: `${PRODUCT_NAME} requested permissions to use ${tool.name}, but you haven't granted it yet.` }; } // For other tools, check persistent permissions default: { const permissionKey = getPermissionKey(tool, input, null); if (allowedTools.includes(permissionKey)) { return { result: true }; } return { result: false, message: `${PRODUCT_NAME} requested permissions to use ${tool.name}, but you haven't granted it yet.` }; } } }; async function savePermission(tool, input, prefix) { const key = getPermissionKey(tool, input, prefix); if (tool === FileEditTool || tool === FileWriteTool || tool === NotebookEditTool) { grantWritePermissionForOriginalDir(); return; } const projectConfig = getCurrentProjectConfig(); if (projectConfig.allowedTools.includes(key)) { return; } projectConfig.allowedTools.push(key); projectConfig.allowedTools.sort(); saveCurrentProjectConfig(projectConfig); } function getPermissionKey(tool, input, prefix) { switch (tool) { case BashTool: if (prefix) { return `${BashTool.name}(${prefix}:*)`; } return `${BashTool.name}(${BashTool.renderToolUseMessage(input)})`; default: return tool.name; } } export { bashToolCommandHasExactMatchPermission, bashToolCommandHasPermission, bashToolHasPermission, hasPermissionsToUseTool, savePermission }; //# sourceMappingURL=permissions.js.map