Implement granular tool permissions (#82)
* Granular tool permissions * Fix build * Start on UI * Fixes * Fmt * Go ham on UI * Update migrations * Considate wiki files * Clean up * More tweaks. Docs. * Consolidate collab and noncollab * Fix build * Restrict for non-collaborators
This commit is contained in:
committed by
pullfrog[bot]
parent
4547b0032e
commit
97dce099c1
@@ -100281,7 +100281,7 @@ function getModes({ disableProgressComment }) {
|
||||
`
|
||||
},
|
||||
{
|
||||
name: "Address Reviews",
|
||||
name: "AddressReviews",
|
||||
description: "Address PR review feedback; respond to reviewer comments; make requested changes to an existing PR",
|
||||
prompt: `Follow these steps. THINK HARDER.
|
||||
1. Checkout the PR using ${ghPullfrogMcpName}/checkout_pr with the PR number. This fetches the PR branch and configures push settings (including for fork PRs).
|
||||
@@ -100406,8 +100406,21 @@ function buildRuntimeContext(repo) {
|
||||
}
|
||||
return lines.join("\n");
|
||||
}
|
||||
var addInstructions = ({ payload, repo }) => {
|
||||
const useNativeBash = !repo.isPublic;
|
||||
function getShellInstructions(bash) {
|
||||
switch (bash) {
|
||||
case "disabled":
|
||||
return `**Shell commands**: Shell command execution is DISABLED. Do not attempt to run shell commands.`;
|
||||
case "restricted":
|
||||
return `**Shell commands**: Use the \`${ghPullfrogMcpName}/bash\` MCP tool for all shell command execution. This tool provides a secure environment with filtered credentials. Do NOT use any native shell/bash tool - it is disabled for security.`;
|
||||
case "enabled":
|
||||
return `**Shell commands**: Use your native bash/shell tool for shell command execution.`;
|
||||
default: {
|
||||
const _exhaustive = bash;
|
||||
return _exhaustive;
|
||||
}
|
||||
}
|
||||
}
|
||||
var addInstructions = ({ payload, repo, tools }) => {
|
||||
let encodedEvent = "";
|
||||
const eventKeys = Object.keys(payload.event);
|
||||
if (eventKeys.length === 1 && eventKeys[0] === "trigger") {
|
||||
@@ -100462,7 +100475,7 @@ Tool names may be formatted as \`(server name)/(tool name)\`, for example: \`${g
|
||||
|
||||
**Efficiency**: Trust the tools - do not repeatedly verify file contents or git status after operations. If a tool reports success, proceed to the next step. Only verify if you encounter an actual error.
|
||||
|
||||
${useNativeBash ? `**Shell commands**: Use your native bash/shell tool for shell command execution.` : `**Shell commands**: Use the \`${ghPullfrogMcpName}/bash\` MCP tool for all shell command execution. This tool provides a secure environment with filtered credentials. Do NOT use any native shell/bash tool - it is disabled for security.`}
|
||||
${getShellInstructions(tools.bash)}
|
||||
|
||||
**Command execution**: Never use \`sleep\` to wait for commands to complete. Commands run synchronously - when the bash tool returns, the command has finished.
|
||||
|
||||
@@ -104622,6 +104635,14 @@ var claudeEffortModels = {
|
||||
auto: "opusplan",
|
||||
max: "opus"
|
||||
};
|
||||
function buildDisallowedTools(tools) {
|
||||
const disallowed = [];
|
||||
if (tools.web === "disabled") disallowed.push("WebFetch");
|
||||
if (tools.search === "disabled") disallowed.push("WebSearch");
|
||||
if (tools.write === "disabled") disallowed.push("Write");
|
||||
if (tools.bash !== "enabled") disallowed.push("Bash");
|
||||
return disallowed;
|
||||
}
|
||||
var claude = agent({
|
||||
name: "claude",
|
||||
install: async () => {
|
||||
@@ -104632,30 +104653,19 @@ var claude = agent({
|
||||
executablePath: "cli.js"
|
||||
});
|
||||
},
|
||||
run: async ({ payload, mcpServers, apiKey, cliPath, repo, effort }) => {
|
||||
run: async ({ payload, mcpServers, apiKey, cliPath, repo, effort, tools }) => {
|
||||
delete process.env.ANTHROPIC_API_KEY;
|
||||
const prompt = addInstructions({ payload, repo });
|
||||
const prompt = addInstructions({ payload, repo, tools });
|
||||
log.group("Full prompt", () => log.info(prompt));
|
||||
const model = claudeEffortModels[effort];
|
||||
log.info(`Using model: ${model} (effort: ${effort})`);
|
||||
const disallowedTools = repo.isPublic ? ["Bash"] : [];
|
||||
const sandboxOptions = payload.sandbox ? {
|
||||
permissionMode: "default",
|
||||
disallowedTools: ["Bash", "WebSearch", "WebFetch", "Write"],
|
||||
async canUseTool(toolName, input, _options) {
|
||||
if (toolName.startsWith("mcp__gh_pullfrog__"))
|
||||
return { behavior: "allow", updatedInput: input, updatedPermissions: [] };
|
||||
return { behavior: "deny", message: "tool not allowed in sandbox mode" };
|
||||
}
|
||||
} : {
|
||||
permissionMode: "bypassPermissions",
|
||||
disallowedTools
|
||||
};
|
||||
if (payload.sandbox) {
|
||||
log.info("\u{1F512} sandbox mode enabled: restricting to read-only operations");
|
||||
const disallowedTools = buildDisallowedTools(tools);
|
||||
if (disallowedTools.length > 0) {
|
||||
log.info(`\u{1F512} disallowed tools: ${disallowedTools.join(", ")}`);
|
||||
}
|
||||
const queryOptions = {
|
||||
...sandboxOptions,
|
||||
permissionMode: "bypassPermissions",
|
||||
disallowedTools,
|
||||
mcpServers,
|
||||
model,
|
||||
pathToClaudeCodeExecutable: cliPath,
|
||||
@@ -105122,32 +105132,35 @@ var codexReasoningEffort = {
|
||||
// use default
|
||||
max: "high"
|
||||
};
|
||||
function writeCodexConfig({ tempHome, mcpServers, isPublicRepo }) {
|
||||
function writeCodexConfig({ tempHome, mcpServers, tools }) {
|
||||
const codexDir = join6(tempHome, ".codex");
|
||||
mkdirSync3(codexDir, { recursive: true });
|
||||
const configPath = join6(codexDir, "config.toml");
|
||||
const mcpServerSections = [];
|
||||
for (const [name, config4] of Object.entries(mcpServers)) {
|
||||
if (config4.type !== "http") continue;
|
||||
log.info(`\xBB Adding MCP server '${name}' at ${config4.url}`);
|
||||
log.info(`\xBB adding MCP server '${name}' at ${config4.url}`);
|
||||
mcpServerSections.push(`[mcp_servers.${name}]
|
||||
url = "${config4.url}"`);
|
||||
}
|
||||
const shellPolicy = isPublicRepo ? `[shell_environment_policy]
|
||||
ignore_default_excludes = false` : "";
|
||||
const features = [];
|
||||
if (tools.bash !== "enabled") {
|
||||
features.push("shell_command_tool = false");
|
||||
features.push("unified_exec = false");
|
||||
}
|
||||
const featuresSection = features.length > 0 ? `[features]
|
||||
${features.join("\n")}` : "";
|
||||
writeFileSync(
|
||||
configPath,
|
||||
`# written by pullfrog
|
||||
${shellPolicy}
|
||||
${featuresSection}
|
||||
|
||||
${mcpServerSections.join("\n\n")}
|
||||
`.trim() + "\n"
|
||||
);
|
||||
if (isPublicRepo) {
|
||||
log.info(`\xBB Codex config written to ${configPath} (env filtering: enabled)`);
|
||||
} else {
|
||||
log.info(`\xBB Codex config written to ${configPath} (private repo: no env filtering)`);
|
||||
}
|
||||
log.info(
|
||||
`\xBB Codex config written to ${configPath} (shell: ${tools.bash === "enabled" ? "enabled" : "disabled"})`
|
||||
);
|
||||
return codexDir;
|
||||
}
|
||||
var codex = agent({
|
||||
@@ -105159,14 +105172,14 @@ var codex = agent({
|
||||
executablePath: "bin/codex.js"
|
||||
});
|
||||
},
|
||||
run: async ({ payload, mcpServers, apiKey, cliPath, repo, effort }) => {
|
||||
run: async ({ payload, mcpServers, apiKey, cliPath, repo, effort, tools }) => {
|
||||
const tempHome = process.env.PULLFROG_TEMP_DIR;
|
||||
const configDir = join6(tempHome, ".config", "codex");
|
||||
mkdirSync3(configDir, { recursive: true });
|
||||
const codexDir = writeCodexConfig({
|
||||
tempHome,
|
||||
mcpServers,
|
||||
isPublicRepo: repo.isPublic
|
||||
tools
|
||||
});
|
||||
setupProcessAgentEnv({
|
||||
OPENAI_API_KEY: apiKey,
|
||||
@@ -105184,26 +105197,24 @@ var codex = agent({
|
||||
apiKey,
|
||||
codexPathOverride: cliPath
|
||||
};
|
||||
if (payload.sandbox) {
|
||||
log.info("\u{1F512} sandbox mode enabled: restricting to read-only operations");
|
||||
}
|
||||
const codex2 = new Codex(codexOptions);
|
||||
const baseThreadOptions = payload.sandbox ? {
|
||||
const threadOptions = {
|
||||
model,
|
||||
approvalPolicy: "never",
|
||||
sandboxMode: "read-only",
|
||||
networkAccessEnabled: false
|
||||
} : {
|
||||
model,
|
||||
approvalPolicy: "never",
|
||||
// use danger-full-access to allow git operations (workspace-write blocks .git directory writes)
|
||||
sandboxMode: "danger-full-access",
|
||||
networkAccessEnabled: true
|
||||
// write: "disabled" → read-only sandbox, otherwise full access for git ops
|
||||
sandboxMode: tools.write === "disabled" ? "read-only" : "danger-full-access",
|
||||
// web: controls network access
|
||||
networkAccessEnabled: tools.web !== "disabled",
|
||||
// search: controls web search
|
||||
webSearchEnabled: tools.search !== "disabled",
|
||||
...modelReasoningEffort && { modelReasoningEffort }
|
||||
};
|
||||
const threadOptions = modelReasoningEffort ? { ...baseThreadOptions, modelReasoningEffort } : baseThreadOptions;
|
||||
log.info(
|
||||
`\u{1F527} Codex options: sandboxMode=${threadOptions.sandboxMode}, networkAccessEnabled=${threadOptions.networkAccessEnabled}, webSearchEnabled=${threadOptions.webSearchEnabled}`
|
||||
);
|
||||
const thread = codex2.startThread(threadOptions);
|
||||
try {
|
||||
const streamedTurn = await thread.runStreamed(addInstructions({ payload, repo }));
|
||||
const streamedTurn = await thread.runStreamed(addInstructions({ payload, repo, tools }));
|
||||
let finalOutput2 = "";
|
||||
for await (const event of streamedTurn.events) {
|
||||
const handler2 = messageHandlers2[event.type];
|
||||
@@ -105330,9 +105341,9 @@ var cursor = agent({
|
||||
executableName: "cursor-agent"
|
||||
});
|
||||
},
|
||||
run: async ({ payload, apiKey, cliPath, mcpServers, repo, effort }) => {
|
||||
run: async ({ payload, apiKey, cliPath, mcpServers, repo, effort, tools }) => {
|
||||
configureCursorMcpServers({ mcpServers, cliPath });
|
||||
configureCursorSandbox({ sandbox: payload.sandbox ?? false, isPublicRepo: repo.isPublic });
|
||||
configureCursorTools({ tools });
|
||||
const projectCliConfigPath = join7(process.cwd(), ".cursor", "cli.json");
|
||||
let modelOverride = null;
|
||||
if (existsSync4(projectCliConfigPath)) {
|
||||
@@ -105404,16 +105415,13 @@ var cursor = agent({
|
||||
}
|
||||
};
|
||||
try {
|
||||
const fullPrompt = addInstructions({ payload, repo });
|
||||
const fullPrompt = addInstructions({ payload, repo, tools });
|
||||
log.group("Full prompt", () => log.info(fullPrompt));
|
||||
const baseArgs = ["--print", fullPrompt, "--output-format", "stream-json", "--approve-mcps"];
|
||||
if (modelOverride) {
|
||||
baseArgs.push("--model", modelOverride);
|
||||
}
|
||||
const cursorArgs = payload.sandbox ? baseArgs : [...baseArgs, "--force"];
|
||||
if (payload.sandbox) {
|
||||
log.info("\u{1F512} sandbox mode enabled: restricting to read-only operations");
|
||||
}
|
||||
const cursorArgs = [...baseArgs, "--force"];
|
||||
log.info("Running Cursor CLI...");
|
||||
const startTime = Date.now();
|
||||
return new Promise((resolve2) => {
|
||||
@@ -105515,29 +105523,32 @@ function configureCursorMcpServers({ mcpServers }) {
|
||||
writeFileSync2(mcpConfigPath, JSON.stringify({ mcpServers: cursorMcpServers }, null, 2), "utf-8");
|
||||
log.info(`\xBB MCP config written to ${mcpConfigPath}`);
|
||||
}
|
||||
function configureCursorSandbox({
|
||||
sandbox,
|
||||
isPublicRepo
|
||||
}) {
|
||||
function configureCursorTools({ tools }) {
|
||||
const realHome = homedir2();
|
||||
const cursorConfigDir = join7(realHome, ".config", "cursor");
|
||||
const cliConfigPath = join7(cursorConfigDir, "cli-config.json");
|
||||
mkdirSync4(cursorConfigDir, { recursive: true });
|
||||
const denyShell = isPublicRepo ? ["Shell(*)"] : [];
|
||||
const config4 = sandbox ? {
|
||||
const deny = [];
|
||||
if (tools.search === "disabled") deny.push("WebSearch");
|
||||
if (tools.write === "disabled") deny.push("Write(**)");
|
||||
if (tools.bash !== "enabled") deny.push("Shell(*)");
|
||||
const needsSandbox = tools.web === "disabled";
|
||||
const config4 = {
|
||||
permissions: {
|
||||
allow: ["Read(**)"],
|
||||
deny: ["Write(**)", ...denyShell]
|
||||
}
|
||||
} : {
|
||||
permissions: {
|
||||
allow: ["Read(**)", "Write(**)"],
|
||||
deny: denyShell
|
||||
allow: tools.write === "disabled" ? ["Read(**)"] : ["Read(**)", "Write(**)"],
|
||||
deny
|
||||
}
|
||||
};
|
||||
if (needsSandbox) {
|
||||
config4.sandbox = {
|
||||
mode: "enabled",
|
||||
networkAccess: "allowlist"
|
||||
};
|
||||
}
|
||||
writeFileSync2(cliConfigPath, JSON.stringify(config4, null, 2), "utf-8");
|
||||
log.info(`\xBB CLI config written to ${cliConfigPath}`);
|
||||
log.info(
|
||||
`\xBB CLI config written to ${cliConfigPath} (sandbox: ${sandbox}, isPublicRepo: ${isPublicRepo})`
|
||||
`\u{1F527} Cursor permissions: allow=${config4.permissions.allow.join(",")}, deny=${deny.join(",") || "(none)"}, sandbox=${needsSandbox ? "enabled" : "disabled"}`
|
||||
);
|
||||
}
|
||||
|
||||
@@ -105714,37 +105725,16 @@ var gemini = agent({
|
||||
...githubInstallationToken2 && { githubInstallationToken: githubInstallationToken2 }
|
||||
});
|
||||
},
|
||||
run: async ({ payload, apiKey, mcpServers, cliPath, repo, effort }) => {
|
||||
run: async ({ payload, apiKey, mcpServers, cliPath, repo, effort, tools }) => {
|
||||
const { model, thinkingLevel } = geminiEffortConfig[effort];
|
||||
log.info(`Using model: ${model}, thinkingLevel: ${thinkingLevel}`);
|
||||
configureGeminiSettings({ mcpServers, isPublicRepo: repo.isPublic, thinkingLevel });
|
||||
configureGeminiSettings({ mcpServers, tools, thinkingLevel });
|
||||
if (!apiKey) {
|
||||
throw new Error("google_api_key or gemini_api_key is required for gemini agent");
|
||||
}
|
||||
const sessionPrompt = addInstructions({ payload, repo });
|
||||
const sessionPrompt = addInstructions({ payload, repo, tools });
|
||||
log.group("Full prompt", () => log.info(sessionPrompt));
|
||||
let args3;
|
||||
if (payload.sandbox) {
|
||||
args3 = [
|
||||
"--model",
|
||||
model,
|
||||
"--allowed-tools",
|
||||
"read_file,list_directory,search_file_content,glob,save_memory,write_todos",
|
||||
"--allowed-mcp-server-names",
|
||||
"gh_pullfrog",
|
||||
"--output-format=stream-json",
|
||||
"-p",
|
||||
sessionPrompt
|
||||
];
|
||||
} else {
|
||||
args3 = ["--model", model, "--yolo", "--output-format=stream-json", "-p", sessionPrompt];
|
||||
if (repo.isPublic) {
|
||||
log.info("\u{1F512} public repo: native shell disabled via excludeTools, using MCP bash");
|
||||
}
|
||||
}
|
||||
if (payload.sandbox) {
|
||||
log.info("\u{1F512} sandbox mode enabled: restricting to read-only operations");
|
||||
}
|
||||
const args3 = ["--model", model, "--yolo", "--output-format=stream-json", "-p", sessionPrompt];
|
||||
let finalOutput2 = "";
|
||||
let stdoutBuffer = "";
|
||||
try {
|
||||
@@ -105810,7 +105800,7 @@ var gemini = agent({
|
||||
});
|
||||
function configureGeminiSettings({
|
||||
mcpServers,
|
||||
isPublicRepo,
|
||||
tools,
|
||||
thinkingLevel
|
||||
}) {
|
||||
const realHome = homedir3();
|
||||
@@ -105835,8 +105825,13 @@ function configureGeminiSettings({
|
||||
trust: true
|
||||
// trust our own MCP server to avoid confirmation prompts
|
||||
};
|
||||
log.info(`Adding MCP server '${serverName}' at ${serverConfig.url}...`);
|
||||
log.info(`adding MCP server '${serverName}' at ${serverConfig.url}...`);
|
||||
}
|
||||
const exclude = [];
|
||||
if (tools.bash !== "enabled") exclude.push("run_shell_command");
|
||||
if (tools.write === "disabled") exclude.push("write_file");
|
||||
if (tools.web === "disabled") exclude.push("web_fetch");
|
||||
if (tools.search === "disabled") exclude.push("google_web_search");
|
||||
const newSettings = {
|
||||
...existingSettings,
|
||||
mcpServers: geminiMcpServers,
|
||||
@@ -105848,13 +105843,15 @@ function configureGeminiSettings({
|
||||
thinkingLevel
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
// v0.3.0+ nested format
|
||||
...exclude.length > 0 && { tools: { exclude } }
|
||||
};
|
||||
if (isPublicRepo) {
|
||||
newSettings.excludeTools = ["run_shell_command"];
|
||||
}
|
||||
writeFileSync3(settingsPath, JSON.stringify(newSettings, null, 2), "utf-8");
|
||||
log.info(`\xBB Gemini settings written to ${settingsPath}`);
|
||||
if (exclude.length > 0) {
|
||||
log.info(`\u{1F512} excluded tools: ${exclude.join(", ")}`);
|
||||
}
|
||||
}
|
||||
|
||||
// agents/opencode.ts
|
||||
@@ -105877,22 +105874,16 @@ var opencode = agent({
|
||||
mcpServers,
|
||||
cliPath,
|
||||
repo,
|
||||
effort: _effort
|
||||
effort: _effort,
|
||||
tools
|
||||
}) => {
|
||||
const tempHome = process.env.PULLFROG_TEMP_DIR;
|
||||
const configDir = join9(tempHome, ".config", "opencode");
|
||||
mkdirSync6(configDir, { recursive: true });
|
||||
configureOpenCode({
|
||||
mcpServers,
|
||||
sandbox: payload.sandbox ?? false,
|
||||
isPublicRepo: repo.isPublic
|
||||
});
|
||||
const prompt = addInstructions({ payload, repo });
|
||||
configureOpenCode({ mcpServers, tools });
|
||||
const prompt = addInstructions({ payload, repo, tools });
|
||||
log.group("Full prompt", () => log.info(prompt));
|
||||
const args3 = ["run", prompt, "--format", "json"];
|
||||
if (payload.sandbox) {
|
||||
log.info("\u{1F512} sandbox mode enabled: restricting to read-only operations");
|
||||
}
|
||||
setupProcessAgentEnv({ HOME: tempHome });
|
||||
const env3 = {
|
||||
...createAgentEnv({ HOME: tempHome }),
|
||||
@@ -106002,7 +105993,7 @@ var opencode = agent({
|
||||
};
|
||||
}
|
||||
});
|
||||
function configureOpenCode({ mcpServers, sandbox, isPublicRepo }) {
|
||||
function configureOpenCode({ mcpServers, tools }) {
|
||||
const tempHome = process.env.PULLFROG_TEMP_DIR;
|
||||
const configDir = join9(tempHome, ".config", "opencode");
|
||||
mkdirSync6(configDir, { recursive: true });
|
||||
@@ -106022,17 +106013,10 @@ function configureOpenCode({ mcpServers, sandbox, isPublicRepo }) {
|
||||
url: serverConfig.url
|
||||
};
|
||||
}
|
||||
const bashPermission = isPublicRepo ? "deny" : "allow";
|
||||
const permission = sandbox ? {
|
||||
edit: "deny",
|
||||
bash: "deny",
|
||||
webfetch: "deny",
|
||||
doom_loop: "allow",
|
||||
external_directory: "allow"
|
||||
} : {
|
||||
edit: "allow",
|
||||
bash: bashPermission,
|
||||
webfetch: "allow",
|
||||
const permission = {
|
||||
edit: tools.write === "disabled" ? "deny" : "allow",
|
||||
bash: tools.bash !== "enabled" ? "deny" : "allow",
|
||||
webfetch: tools.web === "disabled" ? "deny" : "allow",
|
||||
doom_loop: "allow",
|
||||
external_directory: "allow"
|
||||
};
|
||||
@@ -106049,7 +106033,10 @@ function configureOpenCode({ mcpServers, sandbox, isPublicRepo }) {
|
||||
);
|
||||
throw error50;
|
||||
}
|
||||
log.info(`\xBB OpenCode config written to ${configPath} (sandbox: ${sandbox})`);
|
||||
log.info(`\xBB OpenCode config written to ${configPath}`);
|
||||
log.info(
|
||||
`\u{1F527} OpenCode permissions: edit=${permission.edit}, bash=${permission.bash}, webfetch=${permission.webfetch}`
|
||||
);
|
||||
log.debug(`OpenCode config contents:
|
||||
${configJson}`);
|
||||
}
|
||||
@@ -106212,9 +106199,10 @@ var agents = {
|
||||
// utils/api.ts
|
||||
var DEFAULT_REPO_SETTINGS = {
|
||||
defaultAgent: null,
|
||||
webAccessLevel: "full_access",
|
||||
webAccessAllowTrusted: false,
|
||||
webAccessDomains: "",
|
||||
web: "enabled",
|
||||
search: "enabled",
|
||||
write: "enabled",
|
||||
bash: "restricted",
|
||||
modes: []
|
||||
};
|
||||
async function fetchWorkflowRunInfo(runId) {
|
||||
@@ -138323,13 +138311,18 @@ var Timer = class {
|
||||
};
|
||||
|
||||
// main.ts
|
||||
var ToolPermissionInput = type.enumerated("disabled", "enabled");
|
||||
var BashPermissionInput = type.enumerated("disabled", "restricted", "enabled");
|
||||
var Inputs = type({
|
||||
prompt: "string",
|
||||
"effort?": Effort,
|
||||
"agent?": AgentName.or("null"),
|
||||
"event?": "object",
|
||||
"modes?": ModeSchema.array(),
|
||||
"sandbox?": "boolean",
|
||||
"web?": ToolPermissionInput,
|
||||
"search?": ToolPermissionInput,
|
||||
"write?": ToolPermissionInput,
|
||||
"bash?": BashPermissionInput,
|
||||
"disableProgressComment?": "true",
|
||||
"comment_id?": "number|null",
|
||||
"issue_id?": "number|null",
|
||||
@@ -138597,7 +138590,6 @@ function parsePayload(inputs) {
|
||||
event: inputs.event,
|
||||
modes: inputs.modes ?? modes,
|
||||
effort: inputs.effort ?? "auto",
|
||||
sandbox: inputs.sandbox,
|
||||
disableProgressComment: inputs.disableProgressComment,
|
||||
comment_id: inputs.comment_id,
|
||||
issue_id: inputs.issue_id,
|
||||
@@ -138622,8 +138614,7 @@ function parsePayload(inputs) {
|
||||
trigger: "unknown"
|
||||
},
|
||||
modes: inputs.modes ?? modes,
|
||||
effort: inputs.effort ?? "auto",
|
||||
sandbox: inputs.sandbox
|
||||
effort: inputs.effort ?? "auto"
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -138668,6 +138659,14 @@ function validateApiKey(params) {
|
||||
apiKeys
|
||||
};
|
||||
}
|
||||
function computeToolPermissions(params) {
|
||||
return {
|
||||
web: params.inputs.web ?? "enabled",
|
||||
search: params.inputs.search ?? "enabled",
|
||||
write: params.inputs.write ?? "enabled",
|
||||
bash: params.inputs.bash ?? (params.isPublicRepo ? "restricted" : "enabled")
|
||||
};
|
||||
}
|
||||
async function runAgent(ctx) {
|
||||
const effort = ctx.payload.effort ?? "auto";
|
||||
log.info(`Running ${ctx.agent.name} with effort=${effort}...`);
|
||||
@@ -138676,6 +138675,10 @@ async function runAgent(ctx) {
|
||||
|
||||
${encode(eventWithoutContext)}`;
|
||||
log.box(promptContent, { title: "Prompt" });
|
||||
const tools = computeToolPermissions({ inputs: ctx.inputs, isPublicRepo: !ctx.repo.private });
|
||||
log.info(
|
||||
`Tool permissions: web=${tools.web}, search=${tools.search}, write=${tools.write}, bash=${tools.bash}`
|
||||
);
|
||||
return ctx.agent.run({
|
||||
payload: ctx.payload,
|
||||
mcpServers: ctx.mcpServers,
|
||||
@@ -138688,7 +138691,8 @@ ${encode(eventWithoutContext)}`;
|
||||
defaultBranch: ctx.repo.default_branch,
|
||||
isPublic: !ctx.repo.private
|
||||
},
|
||||
effort
|
||||
effort,
|
||||
tools
|
||||
});
|
||||
}
|
||||
async function handleAgentResult(result) {
|
||||
|
||||
Reference in New Issue
Block a user