Switch to payload
This commit is contained in:
+2
-2
@@ -15,11 +15,11 @@ export const claude = agent({
|
||||
executablePath: "cli.js",
|
||||
});
|
||||
},
|
||||
run: async ({ prompt, mcpServers, apiKey, cliPath }) => {
|
||||
run: async ({ payload, mcpServers, apiKey, cliPath }) => {
|
||||
process.env.ANTHROPIC_API_KEY = apiKey;
|
||||
|
||||
const queryInstance = query({
|
||||
prompt: addInstructions(prompt),
|
||||
prompt: addInstructions(payload),
|
||||
options: {
|
||||
permissionMode: "bypassPermissions",
|
||||
mcpServers,
|
||||
|
||||
+2
-2
@@ -14,7 +14,7 @@ export const codex = agent({
|
||||
executablePath: "bin/codex.js",
|
||||
});
|
||||
},
|
||||
run: async ({ prompt, mcpServers, apiKey, cliPath, githubInstallationToken }) => {
|
||||
run: async ({ payload, mcpServers, apiKey, cliPath, githubInstallationToken }) => {
|
||||
process.env.OPENAI_API_KEY = apiKey;
|
||||
process.env.GITHUB_INSTALLATION_TOKEN = githubInstallationToken;
|
||||
|
||||
@@ -39,7 +39,7 @@ export const codex = agent({
|
||||
|
||||
try {
|
||||
// Use runStreamed to get streaming events similar to claude.ts
|
||||
const streamedTurn = await thread.runStreamed(addInstructions(prompt));
|
||||
const streamedTurn = await thread.runStreamed(addInstructions(payload));
|
||||
|
||||
// Stream events and handle them
|
||||
let finalOutput = "";
|
||||
|
||||
+2
-2
@@ -14,7 +14,7 @@ export const cursor = agent({
|
||||
executableName: "cursor-agent",
|
||||
});
|
||||
},
|
||||
run: async ({ prompt, apiKey, cliPath, githubInstallationToken, mcpServers }) => {
|
||||
run: async ({ payload, apiKey, cliPath, githubInstallationToken, mcpServers }) => {
|
||||
process.env.CURSOR_API_KEY = apiKey;
|
||||
process.env.GITHUB_INSTALLATION_TOKEN = githubInstallationToken;
|
||||
|
||||
@@ -24,7 +24,7 @@ export const cursor = agent({
|
||||
// Run cursor-agent in non-interactive mode with the prompt
|
||||
// Using -p flag for prompt, --output-format text for plain text output
|
||||
// and --approve-mcps to automatically approve all MCP servers
|
||||
const fullPrompt = addInstructions(prompt);
|
||||
const fullPrompt = addInstructions(payload);
|
||||
|
||||
// Find temp directory from cliPath to set HOME for MCP config lookup
|
||||
const tempDir = cliPath.split("/.local/bin/")[0];
|
||||
|
||||
+3
-3
@@ -15,7 +15,7 @@ export const gemini = agent({
|
||||
installDependencies: true,
|
||||
});
|
||||
},
|
||||
run: async ({ prompt, apiKey, mcpServers, githubInstallationToken, cliPath }) => {
|
||||
run: async ({ payload, apiKey, mcpServers, githubInstallationToken, cliPath }) => {
|
||||
configureGeminiMcpServers({ mcpServers, cliPath });
|
||||
if (!apiKey) {
|
||||
throw new Error("google_api_key or gemini_api_key is required for gemini agent");
|
||||
@@ -25,8 +25,8 @@ export const gemini = agent({
|
||||
process.env.GEMINI_API_KEY = apiKey;
|
||||
process.env.GITHUB_INSTALLATION_TOKEN = githubInstallationToken;
|
||||
|
||||
const sessionPrompt = addInstructions(prompt);
|
||||
log.info(`Starting Gemini CLI with prompt: ${prompt.substring(0, 100)}...`);
|
||||
const sessionPrompt = addInstructions(payload);
|
||||
log.info(`Starting Gemini CLI with prompt: ${payload.prompt.substring(0, 100)}...`);
|
||||
|
||||
let finalOutput = "";
|
||||
try {
|
||||
|
||||
+12
-8
@@ -1,13 +1,15 @@
|
||||
import { ghPullfrogMcpName } from "../mcp/index.ts";
|
||||
import { modes } from "../modes.ts";
|
||||
import type { Payload } from "../payload.ts";
|
||||
|
||||
const userPromptHeader = `****** USER PROMPT ******\n`;
|
||||
// const userPromptHeader = `************* USER PROMPT *************\n`;
|
||||
|
||||
export const instructions = `
|
||||
export const addInstructions = (payload: Payload) =>
|
||||
`************* GENERAL INSTRUCTIONS *************
|
||||
# General instructions
|
||||
|
||||
You are a diligent, detail-oriented, no-nonsense software engineering agent.
|
||||
You will perform the task that is asked of you below ${userPromptHeader}.
|
||||
You will perform the task described in the *USER PROMPT* below.
|
||||
You are careful, to-the-point, and kind. You only say things you know to be true.
|
||||
You have an extreme bias toward minimalism in your code and responses.
|
||||
Your code is focused, elegant, and production-ready.
|
||||
@@ -48,12 +50,14 @@ Ensure after your edits are done, your final comments do not contain intermediat
|
||||
|
||||
choose the appropriate mode based on the prompt payload:
|
||||
|
||||
${modes.map((w) => ` - "${w.name}": ${w.description}`).join("\n")}
|
||||
${[...modes, ...payload.modes].map((w) => ` - "${w.name}": ${w.description}`).join("\n")}
|
||||
|
||||
## Modes
|
||||
|
||||
${modes.map((w) => `### ${w.name}\n\n${w.prompt}`).join("\n\n")}
|
||||
`;
|
||||
${[...modes, ...payload.modes].map((w) => `### ${w.name}\n\n${w.prompt}`).join("\n\n")}
|
||||
|
||||
export const addInstructions = (prompt: string) =>
|
||||
`****** GENERAL INSTRUCTIONS ******\n${instructions}\n\n${userPromptHeader}${prompt}`;
|
||||
************* USER PROMPT *************
|
||||
|
||||
${payload.prompt}
|
||||
|
||||
${payload.event}`;
|
||||
|
||||
+2
-1
@@ -5,6 +5,7 @@ import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import { pipeline } from "node:stream/promises";
|
||||
import type { McpStdioServerConfig } from "@anthropic-ai/claude-agent-sdk";
|
||||
import type { Payload } from "../payload.ts";
|
||||
import { log } from "../utils/cli.ts";
|
||||
|
||||
/**
|
||||
@@ -23,7 +24,7 @@ export interface AgentResult {
|
||||
export interface AgentConfig {
|
||||
apiKey: string;
|
||||
githubInstallationToken: string;
|
||||
prompt: string;
|
||||
payload: Payload;
|
||||
mcpServers: Record<string, McpStdioServerConfig>;
|
||||
cliPath: string;
|
||||
}
|
||||
|
||||
@@ -32913,12 +32913,13 @@ var package_default = {
|
||||
},
|
||||
dependencies: {
|
||||
"@actions/core": "^1.11.1",
|
||||
"@actions/github": "^6.0.1",
|
||||
"@anthropic-ai/claude-agent-sdk": "0.1.37",
|
||||
"@openai/codex-sdk": "0.58.0",
|
||||
"@ark/fs": "0.53.0",
|
||||
"@ark/util": "0.53.0",
|
||||
"@octokit/rest": "^22.0.0",
|
||||
"@octokit/webhooks-types": "^7.6.1",
|
||||
"@openai/codex-sdk": "0.58.0",
|
||||
"@standard-schema/spec": "1.0.0",
|
||||
arktype: "2.1.25",
|
||||
dotenv: "^17.2.3",
|
||||
@@ -33214,13 +33215,11 @@ var modes = [
|
||||
];
|
||||
|
||||
// agents/instructions.ts
|
||||
var userPromptHeader = `****** USER PROMPT ******
|
||||
`;
|
||||
var instructions = `
|
||||
var addInstructions = (payload) => `************* GENERAL INSTRUCTIONS *************
|
||||
# General instructions
|
||||
|
||||
You are a diligent, detail-oriented, no-nonsense software engineering agent.
|
||||
You will perform the task that is asked of you below ${userPromptHeader}.
|
||||
You will perform the task described in the *USER PROMPT* below.
|
||||
You are careful, to-the-point, and kind. You only say things you know to be true.
|
||||
You have an extreme bias toward minimalism in your code and responses.
|
||||
Your code is focused, elegant, and production-ready.
|
||||
@@ -33261,18 +33260,19 @@ Ensure after your edits are done, your final comments do not contain intermediat
|
||||
|
||||
choose the appropriate mode based on the prompt payload:
|
||||
|
||||
${modes.map((w) => ` - "${w.name}": ${w.description}`).join("\n")}
|
||||
${[...modes, ...payload.modes].map((w) => ` - "${w.name}": ${w.description}`).join("\n")}
|
||||
|
||||
## Modes
|
||||
|
||||
${modes.map((w) => `### ${w.name}
|
||||
${[...modes, ...payload.modes].map((w) => `### ${w.name}
|
||||
|
||||
${w.prompt}`).join("\n\n")}
|
||||
`;
|
||||
var addInstructions = (prompt) => `****** GENERAL INSTRUCTIONS ******
|
||||
${instructions}
|
||||
|
||||
${userPromptHeader}${prompt}`;
|
||||
************* USER PROMPT *************
|
||||
|
||||
${payload.prompt}
|
||||
|
||||
${payload.event}`;
|
||||
|
||||
// agents/shared.ts
|
||||
import { spawnSync } from "node:child_process";
|
||||
@@ -33284,7 +33284,8 @@ import { pipeline } from "node:stream/promises";
|
||||
async function installFromNpmTarball({
|
||||
packageName,
|
||||
version,
|
||||
executablePath
|
||||
executablePath,
|
||||
installDependencies
|
||||
}) {
|
||||
let resolvedVersion = version;
|
||||
if (version.startsWith("^") || version.startsWith("~") || version === "latest") {
|
||||
@@ -33342,6 +33343,20 @@ async function installFromNpmTarball({
|
||||
if (!existsSync2(cliPath)) {
|
||||
throw new Error(`Executable not found in extracted package at ${cliPath}`);
|
||||
}
|
||||
if (installDependencies) {
|
||||
log.info(`Installing dependencies for ${packageName}...`);
|
||||
const installResult = spawnSync("npm", ["install", "--production"], {
|
||||
cwd: extractedDir,
|
||||
stdio: "pipe",
|
||||
encoding: "utf-8"
|
||||
});
|
||||
if (installResult.status !== 0) {
|
||||
throw new Error(
|
||||
`Failed to install dependencies: ${installResult.stderr || installResult.stdout || "Unknown error"}`
|
||||
);
|
||||
}
|
||||
log.info(`\u2713 Dependencies installed`);
|
||||
}
|
||||
chmodSync(cliPath, 493);
|
||||
log.info(`\u2713 ${packageName} installed at ${cliPath}`);
|
||||
return cliPath;
|
||||
@@ -33405,10 +33420,10 @@ var claude = agent({
|
||||
executablePath: "cli.js"
|
||||
});
|
||||
},
|
||||
run: async ({ prompt, mcpServers, apiKey, cliPath }) => {
|
||||
run: async ({ payload, mcpServers, apiKey, cliPath }) => {
|
||||
process.env.ANTHROPIC_API_KEY = apiKey;
|
||||
const queryInstance = query({
|
||||
prompt: addInstructions(prompt),
|
||||
prompt: addInstructions(payload),
|
||||
options: {
|
||||
permissionMode: "bypassPermissions",
|
||||
mcpServers,
|
||||
@@ -33855,12 +33870,10 @@ var codex = agent({
|
||||
executablePath: "bin/codex.js"
|
||||
});
|
||||
},
|
||||
run: async ({ prompt, mcpServers, apiKey, cliPath, githubInstallationToken }) => {
|
||||
run: async ({ payload, mcpServers, apiKey, cliPath, githubInstallationToken }) => {
|
||||
process.env.OPENAI_API_KEY = apiKey;
|
||||
process.env.GITHUB_INSTALLATION_TOKEN = githubInstallationToken;
|
||||
if (mcpServers && Object.keys(mcpServers).length > 0) {
|
||||
configureMcpServers({ mcpServers, apiKey, cliPath });
|
||||
}
|
||||
configureCodexMcpServers({ mcpServers, cliPath });
|
||||
const codexOptions = {
|
||||
apiKey,
|
||||
codexPathOverride: cliPath
|
||||
@@ -33872,7 +33885,7 @@ var codex = agent({
|
||||
networkAccessEnabled: true
|
||||
});
|
||||
try {
|
||||
const streamedTurn = await thread.runStreamed(addInstructions(prompt));
|
||||
const streamedTurn = await thread.runStreamed(addInstructions(payload));
|
||||
let finalOutput = "";
|
||||
for await (const event of streamedTurn.events) {
|
||||
const handler = messageHandlers2[event.type];
|
||||
@@ -33968,17 +33981,8 @@ var messageHandlers2 = {
|
||||
log.error(`Error: ${event.message}`);
|
||||
}
|
||||
};
|
||||
function configureMcpServers({
|
||||
mcpServers,
|
||||
apiKey,
|
||||
cliPath
|
||||
}) {
|
||||
log.info("Configuring MCP servers for Codex...");
|
||||
function configureCodexMcpServers({ mcpServers, cliPath }) {
|
||||
for (const [serverName, serverConfig] of Object.entries(mcpServers)) {
|
||||
if (!("command" in serverConfig)) {
|
||||
log.warning(`MCP server '${serverName}' is not a stdio server, skipping...`);
|
||||
continue;
|
||||
}
|
||||
const command = serverConfig.command;
|
||||
const args2 = serverConfig.args || [];
|
||||
const envVars = serverConfig.env || {};
|
||||
@@ -33990,11 +33994,7 @@ function configureMcpServers({
|
||||
log.info(`Adding MCP server '${serverName}'...`);
|
||||
const addResult = spawnSync2("node", [cliPath, ...addArgs], {
|
||||
stdio: "pipe",
|
||||
encoding: "utf-8",
|
||||
env: {
|
||||
...process.env,
|
||||
OPENAI_API_KEY: apiKey
|
||||
}
|
||||
encoding: "utf-8"
|
||||
});
|
||||
if (addResult.status !== 0) {
|
||||
throw new Error(
|
||||
@@ -34011,27 +34011,25 @@ import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync2 } from "node:f
|
||||
import { join as join5 } from "node:path";
|
||||
var cursor = agent({
|
||||
name: "cursor",
|
||||
inputKey: "cursor_api_key",
|
||||
inputKeys: ["cursor_api_key"],
|
||||
install: async () => {
|
||||
return await installFromCurl({
|
||||
installUrl: "https://cursor.com/install",
|
||||
executableName: "cursor-agent"
|
||||
});
|
||||
},
|
||||
run: async ({ prompt, mcpServers, apiKey, cliPath, githubInstallationToken }) => {
|
||||
run: async ({ payload, apiKey, cliPath, githubInstallationToken, mcpServers }) => {
|
||||
process.env.CURSOR_API_KEY = apiKey;
|
||||
process.env.GITHUB_INSTALLATION_TOKEN = githubInstallationToken;
|
||||
if (mcpServers && Object.keys(mcpServers).length > 0) {
|
||||
configureMcpServers2({ mcpServers, cliPath });
|
||||
}
|
||||
configureCursorMcpServers({ mcpServers, cliPath });
|
||||
try {
|
||||
const fullPrompt = addInstructions(prompt);
|
||||
const fullPrompt = addInstructions(payload);
|
||||
const tempDir = cliPath.split("/.local/bin/")[0];
|
||||
log.info("Running Cursor CLI...");
|
||||
return new Promise((resolve) => {
|
||||
const child = spawn3(
|
||||
cliPath,
|
||||
["--print", fullPrompt, "--output-format", "text", "--approve-mcps"],
|
||||
["--print", fullPrompt, "--output-format", "text", "--approve-mcps", "--force"],
|
||||
{
|
||||
cwd: process.cwd(),
|
||||
// Run in current working directory
|
||||
@@ -34048,37 +34046,31 @@ var cursor = agent({
|
||||
);
|
||||
let stdout = "";
|
||||
let stderr = "";
|
||||
let hasOutput = false;
|
||||
const timeout = setTimeout(() => {
|
||||
if (!hasOutput && child.exitCode === null) {
|
||||
log.warning("Cursor CLI appears to be hanging, killing process...");
|
||||
child.kill("SIGTERM");
|
||||
resolve({
|
||||
success: false,
|
||||
error: "Cursor CLI timed out - no output received",
|
||||
output: stdout.trim()
|
||||
});
|
||||
}
|
||||
}, 3e5);
|
||||
child.on("spawn", () => {
|
||||
log.debug("Cursor CLI process spawned");
|
||||
});
|
||||
child.stdout?.on("data", (data) => {
|
||||
hasOutput = true;
|
||||
const text = data.toString();
|
||||
stdout += text;
|
||||
process.stdout.write(text);
|
||||
});
|
||||
child.stderr?.on("data", (data) => {
|
||||
hasOutput = true;
|
||||
const text = data.toString();
|
||||
stderr += text;
|
||||
process.stderr.write(text);
|
||||
log.warning(text);
|
||||
});
|
||||
child.on("close", (code) => {
|
||||
clearTimeout(timeout);
|
||||
if (code !== 0) {
|
||||
child.on("close", (code, signal) => {
|
||||
if (signal) {
|
||||
log.warning(`Cursor CLI terminated by signal: ${signal}`);
|
||||
}
|
||||
if (code === 0) {
|
||||
log.success("Cursor CLI completed successfully");
|
||||
resolve({
|
||||
success: true,
|
||||
output: stdout.trim()
|
||||
});
|
||||
} else {
|
||||
const errorMessage = stderr || `Cursor CLI exited with code ${code}`;
|
||||
log.error(`Cursor CLI failed: ${errorMessage}`);
|
||||
resolve({
|
||||
@@ -34109,222 +34101,16 @@ var cursor = agent({
|
||||
}
|
||||
}
|
||||
});
|
||||
function configureMcpServers2({
|
||||
mcpServers,
|
||||
cliPath
|
||||
}) {
|
||||
log.info("Configuring MCP servers for Cursor...");
|
||||
function configureCursorMcpServers({ mcpServers, cliPath }) {
|
||||
const tempDir = cliPath.split("/.local/bin/")[0];
|
||||
const cursorConfigDir = join5(tempDir, ".cursor");
|
||||
const mcpConfigPath = join5(cursorConfigDir, "mcp.json");
|
||||
const mcpConfig = {
|
||||
mcpServers: {}
|
||||
};
|
||||
for (const [serverName, serverConfig] of Object.entries(mcpServers)) {
|
||||
if (!("command" in serverConfig)) {
|
||||
log.warning(`MCP server '${serverName}' is not a stdio server, skipping...`);
|
||||
continue;
|
||||
}
|
||||
mcpConfig.mcpServers[serverName] = serverConfig;
|
||||
log.info(`Adding MCP server '${serverName}'...`);
|
||||
}
|
||||
if (Object.keys(mcpConfig.mcpServers).length === 0) {
|
||||
log.info("No MCP servers to configure");
|
||||
return;
|
||||
}
|
||||
mkdirSync2(cursorConfigDir, { recursive: true });
|
||||
writeFileSync2(mcpConfigPath, JSON.stringify(mcpConfig, null, 2), "utf-8");
|
||||
log.info(`\u2713 MCP configuration written to ${mcpConfigPath}`);
|
||||
log.info("MCP servers configured. Cursor CLI will use --approve-mcps to auto-approve servers.");
|
||||
writeFileSync2(mcpConfigPath, JSON.stringify({ mcpServers }, null, 2), "utf-8");
|
||||
}
|
||||
|
||||
// utils/github.ts
|
||||
var core2 = __toESM(require_core(), 1);
|
||||
import { createSign } from "node:crypto";
|
||||
function checkExistingToken() {
|
||||
const inputToken = core2.getInput("github_installation_token");
|
||||
const envToken = process.env.GITHUB_INSTALLATION_TOKEN;
|
||||
return inputToken || envToken || null;
|
||||
}
|
||||
function isGitHubActionsEnvironment() {
|
||||
return Boolean(process.env.GITHUB_ACTIONS);
|
||||
}
|
||||
async function acquireTokenViaOIDC() {
|
||||
log.info("Generating OIDC token...");
|
||||
const oidcToken = await core2.getIDToken("pullfrog-api");
|
||||
log.info("OIDC token generated successfully");
|
||||
const apiUrl = process.env.API_URL || "https://pullfrog.ai";
|
||||
log.info("Exchanging OIDC token for installation token...");
|
||||
const timeoutMs = 5e3;
|
||||
const controller = new AbortController();
|
||||
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
||||
try {
|
||||
const tokenResponse = await fetch(`${apiUrl}/api/github/installation-token`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
Authorization: `Bearer ${oidcToken}`,
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
signal: controller.signal
|
||||
});
|
||||
clearTimeout(timeoutId);
|
||||
if (!tokenResponse.ok) {
|
||||
throw new Error(`Token exchange failed: ${tokenResponse.status} ${tokenResponse.statusText}`);
|
||||
}
|
||||
const tokenData = await tokenResponse.json();
|
||||
log.info(`Installation token obtained for ${tokenData.repository || "all repositories"}`);
|
||||
return tokenData.token;
|
||||
} catch (error2) {
|
||||
clearTimeout(timeoutId);
|
||||
if (error2 instanceof Error && error2.name === "AbortError") {
|
||||
throw new Error(`Token exchange timed out after ${timeoutMs}ms`);
|
||||
}
|
||||
throw error2;
|
||||
}
|
||||
}
|
||||
var base64UrlEncode = (str) => {
|
||||
return Buffer.from(str).toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
||||
};
|
||||
var generateJWT = (appId, privateKey) => {
|
||||
const now = Math.floor(Date.now() / 1e3);
|
||||
const payload = {
|
||||
iat: now - 60,
|
||||
exp: now + 5 * 60,
|
||||
iss: appId
|
||||
};
|
||||
const header = {
|
||||
alg: "RS256",
|
||||
typ: "JWT"
|
||||
};
|
||||
const encodedHeader = base64UrlEncode(JSON.stringify(header));
|
||||
const encodedPayload = base64UrlEncode(JSON.stringify(payload));
|
||||
const signaturePart = `${encodedHeader}.${encodedPayload}`;
|
||||
const signature = createSign("RSA-SHA256").update(signaturePart).sign(privateKey, "base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
||||
return `${signaturePart}.${signature}`;
|
||||
};
|
||||
var githubRequest = async (path4, options = {}) => {
|
||||
const { method = "GET", headers = {}, body } = options;
|
||||
const url2 = `https://api.github.com${path4}`;
|
||||
const requestHeaders = {
|
||||
Accept: "application/vnd.github.v3+json",
|
||||
"User-Agent": "Pullfrog-Installation-Token-Generator/1.0",
|
||||
...headers
|
||||
};
|
||||
const response = await fetch(url2, {
|
||||
method,
|
||||
headers: requestHeaders,
|
||||
...body && { body }
|
||||
});
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text();
|
||||
throw new Error(
|
||||
`GitHub API request failed: ${response.status} ${response.statusText}
|
||||
${errorText}`
|
||||
);
|
||||
}
|
||||
return response.json();
|
||||
};
|
||||
var checkRepositoryAccess = async (token, repoOwner, repoName) => {
|
||||
try {
|
||||
const response = await githubRequest("/installation/repositories", {
|
||||
headers: { Authorization: `token ${token}` }
|
||||
});
|
||||
return response.repositories.some(
|
||||
(repo) => repo.owner.login === repoOwner && repo.name === repoName
|
||||
);
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
var createInstallationToken = async (jwt, installationId) => {
|
||||
const response = await githubRequest(
|
||||
`/app/installations/${installationId}/access_tokens`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: { Authorization: `Bearer ${jwt}` }
|
||||
}
|
||||
);
|
||||
return response.token;
|
||||
};
|
||||
var findInstallationId = async (jwt, repoOwner, repoName) => {
|
||||
const installations = await githubRequest("/app/installations", {
|
||||
headers: { Authorization: `Bearer ${jwt}` }
|
||||
});
|
||||
for (const installation of installations) {
|
||||
try {
|
||||
const tempToken = await createInstallationToken(jwt, installation.id);
|
||||
const hasAccess = await checkRepositoryAccess(tempToken, repoOwner, repoName);
|
||||
if (hasAccess) {
|
||||
return installation.id;
|
||||
}
|
||||
} catch {
|
||||
}
|
||||
}
|
||||
throw new Error(
|
||||
`No installation found with access to ${repoOwner}/${repoName}. Ensure the GitHub App is installed on the target repository.`
|
||||
);
|
||||
};
|
||||
async function acquireTokenViaGitHubApp() {
|
||||
const repoContext = parseRepoContext();
|
||||
const config = {
|
||||
appId: process.env.GITHUB_APP_ID,
|
||||
privateKey: process.env.GITHUB_PRIVATE_KEY?.replace(/\\n/g, "\n"),
|
||||
repoOwner: repoContext.owner,
|
||||
repoName: repoContext.name
|
||||
};
|
||||
const jwt = generateJWT(config.appId, config.privateKey);
|
||||
const installationId = await findInstallationId(jwt, config.repoOwner, config.repoName);
|
||||
const token = await createInstallationToken(jwt, installationId);
|
||||
return token;
|
||||
}
|
||||
async function acquireNewToken() {
|
||||
if (isGitHubActionsEnvironment()) {
|
||||
return await acquireTokenViaOIDC();
|
||||
} else {
|
||||
return await acquireTokenViaGitHubApp();
|
||||
}
|
||||
}
|
||||
async function setupGitHubInstallationToken() {
|
||||
const existingToken = checkExistingToken();
|
||||
if (existingToken) {
|
||||
core2.setSecret(existingToken);
|
||||
log.info("Using provided GitHub installation token");
|
||||
return { githubInstallationToken: existingToken, wasAcquired: false };
|
||||
}
|
||||
const acquiredToken = await acquireNewToken();
|
||||
core2.setSecret(acquiredToken);
|
||||
process.env.GITHUB_INSTALLATION_TOKEN = acquiredToken;
|
||||
return { githubInstallationToken: acquiredToken, wasAcquired: true };
|
||||
}
|
||||
async function revokeInstallationToken(token) {
|
||||
const apiUrl = process.env.GITHUB_API_URL || "https://api.github.com";
|
||||
try {
|
||||
await fetch(`${apiUrl}/installation/token`, {
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
Accept: "application/vnd.github+json",
|
||||
Authorization: `Bearer ${token}`,
|
||||
"X-GitHub-Api-Version": "2022-11-28"
|
||||
}
|
||||
});
|
||||
log.info("Installation token revoked");
|
||||
} catch (error2) {
|
||||
log.warning(
|
||||
`Failed to revoke installation token: ${error2 instanceof Error ? error2.message : String(error2)}`
|
||||
);
|
||||
}
|
||||
}
|
||||
function parseRepoContext() {
|
||||
const githubRepo = process.env.GITHUB_REPOSITORY;
|
||||
if (!githubRepo) {
|
||||
throw new Error("GITHUB_REPOSITORY environment variable is required");
|
||||
}
|
||||
const [owner, name] = githubRepo.split("/");
|
||||
if (!owner || !name) {
|
||||
throw new Error(`Invalid GITHUB_REPOSITORY format: ${githubRepo}. Expected 'owner/repo'`);
|
||||
}
|
||||
return { owner, name };
|
||||
}
|
||||
// agents/gemini.ts
|
||||
import { spawnSync as spawnSync3 } from "node:child_process";
|
||||
|
||||
// utils/subprocess.ts
|
||||
import { spawn as nodeSpawn } from "node:child_process";
|
||||
@@ -34401,151 +34187,106 @@ async function spawn4(options) {
|
||||
});
|
||||
}
|
||||
|
||||
// agents/jules.ts
|
||||
var jules = agent({
|
||||
name: "jules",
|
||||
// agents/gemini.ts
|
||||
var gemini = agent({
|
||||
name: "gemini",
|
||||
inputKeys: ["google_api_key", "gemini_api_key"],
|
||||
install: async () => {
|
||||
return await installFromNpmTarball({
|
||||
packageName: "@google/jules",
|
||||
packageName: "@google/gemini-cli",
|
||||
version: "latest",
|
||||
executablePath: "run.cjs"
|
||||
executablePath: "dist/index.js",
|
||||
installDependencies: true
|
||||
});
|
||||
},
|
||||
run: async ({
|
||||
prompt,
|
||||
apiKey,
|
||||
mcpServers: _mcpServers,
|
||||
githubInstallationToken: _githubInstallationToken,
|
||||
cliPath
|
||||
}) => {
|
||||
run: async ({ payload, apiKey, mcpServers, githubInstallationToken, cliPath }) => {
|
||||
configureGeminiMcpServers({ mcpServers, cliPath });
|
||||
if (!apiKey) {
|
||||
throw new Error("google_api_key is required for jules agent");
|
||||
throw new Error("google_api_key or gemini_api_key is required for gemini agent");
|
||||
}
|
||||
process.env.GOOGLE_API_KEY = apiKey;
|
||||
const repoContext = parseRepoContext();
|
||||
const repoName = `${repoContext.owner}/${repoContext.name}`;
|
||||
log.info(`Creating Jules session for ${repoName}...`);
|
||||
const sessionPrompt = addInstructions(prompt);
|
||||
log.info(`Starting session with prompt: ${prompt.substring(0, 100)}...`);
|
||||
let sessionId;
|
||||
process.env.GEMINI_API_KEY = apiKey;
|
||||
process.env.GITHUB_INSTALLATION_TOKEN = githubInstallationToken;
|
||||
const sessionPrompt = addInstructions(payload);
|
||||
log.info(`Starting Gemini CLI with prompt: ${payload.prompt.substring(0, 100)}...`);
|
||||
let finalOutput = "";
|
||||
try {
|
||||
const createResult = await spawn4({
|
||||
const result = await spawn4({
|
||||
cmd: "node",
|
||||
args: [cliPath, "remote", "new", "--repo", repoName, "--session", sessionPrompt],
|
||||
args: [cliPath, "--yolo", "--output-format", "text", sessionPrompt],
|
||||
env: {
|
||||
GEMINI_API_KEY: apiKey,
|
||||
GITHUB_INSTALLATION_TOKEN: githubInstallationToken
|
||||
},
|
||||
onStdout: (chunk) => {
|
||||
log.info(chunk.trim());
|
||||
const match2 = chunk.match(/session[:\s]+(\d+)/i) || chunk.match(/id[:\s]+(\d+)/i);
|
||||
if (match2 && !sessionId) {
|
||||
sessionId = match2[1];
|
||||
log.info(`\u2713 Session ID: ${sessionId}`);
|
||||
const trimmed = chunk.trim();
|
||||
if (trimmed) {
|
||||
log.info(trimmed);
|
||||
finalOutput += trimmed + "\n";
|
||||
}
|
||||
},
|
||||
onStderr: (chunk) => {
|
||||
log.warning(chunk.trim());
|
||||
const trimmed = chunk.trim();
|
||||
if (trimmed) {
|
||||
log.warning(trimmed);
|
||||
finalOutput += trimmed + "\n";
|
||||
}
|
||||
}
|
||||
});
|
||||
if (createResult.exitCode !== 0) {
|
||||
throw new Error(
|
||||
`Failed to create Jules session: ${createResult.stderr || createResult.stdout || "Unknown error"}`
|
||||
);
|
||||
}
|
||||
if (!sessionId) {
|
||||
const output = createResult.stdout + createResult.stderr;
|
||||
const match2 = output.match(/session[:\s]+(\d+)/i) || output.match(/id[:\s]+(\d+)/i);
|
||||
if (match2) {
|
||||
sessionId = match2[1];
|
||||
}
|
||||
}
|
||||
if (!sessionId) {
|
||||
log.warning("Could not extract session ID from output. Session may have been created.");
|
||||
log.info(`Output: ${createResult.stdout}`);
|
||||
} else {
|
||||
log.info(`\u2713 Session created: ${sessionId}`);
|
||||
if (result.exitCode !== 0) {
|
||||
const errorMessage = result.stderr || result.stdout || "Unknown error";
|
||||
log.error(`Gemini CLI exited with code ${result.exitCode}: ${errorMessage}`);
|
||||
return {
|
||||
success: false,
|
||||
error: errorMessage,
|
||||
output: finalOutput || result.stdout || ""
|
||||
};
|
||||
}
|
||||
finalOutput = finalOutput || result.stdout || "Gemini CLI completed successfully.";
|
||||
log.info("\u2713 Gemini CLI completed successfully");
|
||||
return {
|
||||
success: true,
|
||||
output: finalOutput
|
||||
};
|
||||
} catch (error2) {
|
||||
const errorMessage = error2 instanceof Error ? error2.message : String(error2);
|
||||
log.error(`Failed to create Jules session: ${errorMessage}`);
|
||||
log.error(`Failed to run Gemini CLI: ${errorMessage}`);
|
||||
return {
|
||||
success: false,
|
||||
error: errorMessage,
|
||||
output: ""
|
||||
output: finalOutput || ""
|
||||
};
|
||||
}
|
||||
log.info("Monitoring session progress...");
|
||||
let finalOutput = "";
|
||||
const maxPollAttempts = 300;
|
||||
let pollAttempts = 0;
|
||||
while (pollAttempts < maxPollAttempts) {
|
||||
await new Promise((resolve) => setTimeout(resolve, 1e4));
|
||||
pollAttempts++;
|
||||
try {
|
||||
const listResult = await spawn4({
|
||||
cmd: "node",
|
||||
args: [cliPath, "remote", "list", "--session"],
|
||||
onStdout: (chunk) => {
|
||||
const trimmed = chunk.trim();
|
||||
if (trimmed) {
|
||||
log.info(trimmed);
|
||||
}
|
||||
}
|
||||
});
|
||||
if (listResult.exitCode === 0) {
|
||||
const output = listResult.stdout;
|
||||
if (sessionId && output.includes(sessionId)) {
|
||||
if (output.includes("completed") || output.includes("done") || output.includes("finished")) {
|
||||
log.info("Session appears to be completed");
|
||||
finalOutput = "Session completed. Pulling results...";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error2) {
|
||||
const errorMessage = error2 instanceof Error ? error2.message : String(error2);
|
||||
log.warning(`Error checking session status: ${errorMessage}`);
|
||||
}
|
||||
}
|
||||
if (sessionId) {
|
||||
try {
|
||||
log.info(`Pulling results for session ${sessionId}...`);
|
||||
const pullResult = await spawn4({
|
||||
cmd: "node",
|
||||
args: [cliPath, "remote", "pull", "--session", sessionId],
|
||||
onStdout: (chunk) => {
|
||||
log.info(chunk.trim());
|
||||
},
|
||||
onStderr: (chunk) => {
|
||||
log.warning(chunk.trim());
|
||||
}
|
||||
});
|
||||
if (pullResult.exitCode === 0) {
|
||||
finalOutput = pullResult.stdout || "Results pulled successfully.";
|
||||
} else {
|
||||
log.warning(`Failed to pull results: ${pullResult.stderr || pullResult.stdout}`);
|
||||
finalOutput = finalOutput || "Session completed. Check Jules dashboard for results.";
|
||||
}
|
||||
} catch (error2) {
|
||||
const errorMessage = error2 instanceof Error ? error2.message : String(error2);
|
||||
log.warning(`Error pulling results: ${errorMessage}`);
|
||||
}
|
||||
}
|
||||
if (pollAttempts >= maxPollAttempts) {
|
||||
log.warning("Session monitoring timeout reached. Session may still be in progress.");
|
||||
finalOutput = finalOutput || "Session monitoring timeout. Check Jules dashboard for session status.";
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
output: finalOutput || "Jules session completed. Check the Jules dashboard for results."
|
||||
};
|
||||
}
|
||||
});
|
||||
function configureGeminiMcpServers({ mcpServers, cliPath }) {
|
||||
for (const [serverName, serverConfig] of Object.entries(mcpServers)) {
|
||||
const command = serverConfig.command;
|
||||
const args2 = serverConfig.args || [];
|
||||
const envVars = serverConfig.env || {};
|
||||
const addArgs = ["mcp", "add", serverName, command, ...args2];
|
||||
for (const [key, value2] of Object.entries(envVars)) {
|
||||
addArgs.push("--env", `${key}=${value2}`);
|
||||
}
|
||||
log.info(`Adding MCP server '${serverName}'...`);
|
||||
const addResult = spawnSync3("node", [cliPath, ...addArgs], {
|
||||
stdio: "pipe",
|
||||
encoding: "utf-8"
|
||||
});
|
||||
if (addResult.status !== 0) {
|
||||
throw new Error(
|
||||
`gemini mcp add failed: ${addResult.stderr || addResult.stdout || "Unknown error"}`
|
||||
);
|
||||
}
|
||||
log.info(`\u2713 MCP server '${serverName}' configured`);
|
||||
}
|
||||
}
|
||||
|
||||
// agents/index.ts
|
||||
var agents = {
|
||||
claude,
|
||||
codex,
|
||||
cursor,
|
||||
jules
|
||||
gemini
|
||||
};
|
||||
|
||||
// node_modules/.pnpm/@ark+schema@0.53.0/node_modules/@ark/schema/out/shared/registry.js
|
||||
@@ -42292,6 +42033,194 @@ var dirOfCaller = () => dirname2(filePath(caller({ methodName: "dirOfCaller", up
|
||||
var fromHere = (...joinWith) => join6(dirOfCaller(), ...joinWith);
|
||||
var fsRoot = parse(process3.cwd()).root;
|
||||
|
||||
// utils/github.ts
|
||||
var core2 = __toESM(require_core(), 1);
|
||||
import { createSign } from "node:crypto";
|
||||
function checkExistingToken() {
|
||||
const inputToken = core2.getInput("github_installation_token");
|
||||
const envToken = process.env.GITHUB_INSTALLATION_TOKEN;
|
||||
return inputToken || envToken || null;
|
||||
}
|
||||
function isGitHubActionsEnvironment() {
|
||||
return Boolean(process.env.GITHUB_ACTIONS);
|
||||
}
|
||||
async function acquireTokenViaOIDC() {
|
||||
log.info("Generating OIDC token...");
|
||||
const oidcToken = await core2.getIDToken("pullfrog-api");
|
||||
log.info("OIDC token generated successfully");
|
||||
const apiUrl = process.env.API_URL || "https://pullfrog.ai";
|
||||
log.info("Exchanging OIDC token for installation token...");
|
||||
const timeoutMs = 5e3;
|
||||
const controller = new AbortController();
|
||||
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
||||
try {
|
||||
const tokenResponse = await fetch(`${apiUrl}/api/github/installation-token`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
Authorization: `Bearer ${oidcToken}`,
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
signal: controller.signal
|
||||
});
|
||||
clearTimeout(timeoutId);
|
||||
if (!tokenResponse.ok) {
|
||||
throw new Error(`Token exchange failed: ${tokenResponse.status} ${tokenResponse.statusText}`);
|
||||
}
|
||||
const tokenData = await tokenResponse.json();
|
||||
log.info(`Installation token obtained for ${tokenData.repository || "all repositories"}`);
|
||||
return tokenData.token;
|
||||
} catch (error2) {
|
||||
clearTimeout(timeoutId);
|
||||
if (error2 instanceof Error && error2.name === "AbortError") {
|
||||
throw new Error(`Token exchange timed out after ${timeoutMs}ms`);
|
||||
}
|
||||
throw error2;
|
||||
}
|
||||
}
|
||||
var base64UrlEncode = (str) => {
|
||||
return Buffer.from(str).toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
||||
};
|
||||
var generateJWT = (appId, privateKey) => {
|
||||
const now = Math.floor(Date.now() / 1e3);
|
||||
const payload = {
|
||||
iat: now - 60,
|
||||
exp: now + 5 * 60,
|
||||
iss: appId
|
||||
};
|
||||
const header = {
|
||||
alg: "RS256",
|
||||
typ: "JWT"
|
||||
};
|
||||
const encodedHeader = base64UrlEncode(JSON.stringify(header));
|
||||
const encodedPayload = base64UrlEncode(JSON.stringify(payload));
|
||||
const signaturePart = `${encodedHeader}.${encodedPayload}`;
|
||||
const signature = createSign("RSA-SHA256").update(signaturePart).sign(privateKey, "base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
||||
return `${signaturePart}.${signature}`;
|
||||
};
|
||||
var githubRequest = async (path4, options = {}) => {
|
||||
const { method = "GET", headers = {}, body } = options;
|
||||
const url2 = `https://api.github.com${path4}`;
|
||||
const requestHeaders = {
|
||||
Accept: "application/vnd.github.v3+json",
|
||||
"User-Agent": "Pullfrog-Installation-Token-Generator/1.0",
|
||||
...headers
|
||||
};
|
||||
const response = await fetch(url2, {
|
||||
method,
|
||||
headers: requestHeaders,
|
||||
...body && { body }
|
||||
});
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text();
|
||||
throw new Error(
|
||||
`GitHub API request failed: ${response.status} ${response.statusText}
|
||||
${errorText}`
|
||||
);
|
||||
}
|
||||
return response.json();
|
||||
};
|
||||
var checkRepositoryAccess = async (token, repoOwner, repoName) => {
|
||||
try {
|
||||
const response = await githubRequest("/installation/repositories", {
|
||||
headers: { Authorization: `token ${token}` }
|
||||
});
|
||||
return response.repositories.some(
|
||||
(repo) => repo.owner.login === repoOwner && repo.name === repoName
|
||||
);
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
var createInstallationToken = async (jwt, installationId) => {
|
||||
const response = await githubRequest(
|
||||
`/app/installations/${installationId}/access_tokens`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: { Authorization: `Bearer ${jwt}` }
|
||||
}
|
||||
);
|
||||
return response.token;
|
||||
};
|
||||
var findInstallationId = async (jwt, repoOwner, repoName) => {
|
||||
const installations = await githubRequest("/app/installations", {
|
||||
headers: { Authorization: `Bearer ${jwt}` }
|
||||
});
|
||||
for (const installation of installations) {
|
||||
try {
|
||||
const tempToken = await createInstallationToken(jwt, installation.id);
|
||||
const hasAccess = await checkRepositoryAccess(tempToken, repoOwner, repoName);
|
||||
if (hasAccess) {
|
||||
return installation.id;
|
||||
}
|
||||
} catch {
|
||||
}
|
||||
}
|
||||
throw new Error(
|
||||
`No installation found with access to ${repoOwner}/${repoName}. Ensure the GitHub App is installed on the target repository.`
|
||||
);
|
||||
};
|
||||
async function acquireTokenViaGitHubApp() {
|
||||
const repoContext = parseRepoContext();
|
||||
const config = {
|
||||
appId: process.env.GITHUB_APP_ID,
|
||||
privateKey: process.env.GITHUB_PRIVATE_KEY?.replace(/\\n/g, "\n"),
|
||||
repoOwner: repoContext.owner,
|
||||
repoName: repoContext.name
|
||||
};
|
||||
const jwt = generateJWT(config.appId, config.privateKey);
|
||||
const installationId = await findInstallationId(jwt, config.repoOwner, config.repoName);
|
||||
const token = await createInstallationToken(jwt, installationId);
|
||||
return token;
|
||||
}
|
||||
async function acquireNewToken() {
|
||||
if (isGitHubActionsEnvironment()) {
|
||||
return await acquireTokenViaOIDC();
|
||||
} else {
|
||||
return await acquireTokenViaGitHubApp();
|
||||
}
|
||||
}
|
||||
async function setupGitHubInstallationToken() {
|
||||
const existingToken = checkExistingToken();
|
||||
if (existingToken) {
|
||||
core2.setSecret(existingToken);
|
||||
log.info("Using provided GitHub installation token");
|
||||
return { githubInstallationToken: existingToken, wasAcquired: false };
|
||||
}
|
||||
const acquiredToken = await acquireNewToken();
|
||||
core2.setSecret(acquiredToken);
|
||||
process.env.GITHUB_INSTALLATION_TOKEN = acquiredToken;
|
||||
return { githubInstallationToken: acquiredToken, wasAcquired: true };
|
||||
}
|
||||
async function revokeInstallationToken(token) {
|
||||
const apiUrl = process.env.GITHUB_API_URL || "https://api.github.com";
|
||||
try {
|
||||
await fetch(`${apiUrl}/installation/token`, {
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
Accept: "application/vnd.github+json",
|
||||
Authorization: `Bearer ${token}`,
|
||||
"X-GitHub-Api-Version": "2022-11-28"
|
||||
}
|
||||
});
|
||||
log.info("Installation token revoked");
|
||||
} catch (error2) {
|
||||
log.warning(
|
||||
`Failed to revoke installation token: ${error2 instanceof Error ? error2.message : String(error2)}`
|
||||
);
|
||||
}
|
||||
}
|
||||
function parseRepoContext() {
|
||||
const githubRepo = process.env.GITHUB_REPOSITORY;
|
||||
if (!githubRepo) {
|
||||
throw new Error("GITHUB_REPOSITORY environment variable is required");
|
||||
}
|
||||
const [owner, name] = githubRepo.split("/");
|
||||
if (!owner || !name) {
|
||||
throw new Error(`Invalid GITHUB_REPOSITORY format: ${githubRepo}. Expected 'owner/repo'`);
|
||||
}
|
||||
return { owner, name };
|
||||
}
|
||||
|
||||
// mcp/config.ts
|
||||
function createMcpConfigs(githubInstallationToken) {
|
||||
const repoContext = parseRepoContext();
|
||||
@@ -42460,7 +42389,23 @@ async function main(inputs) {
|
||||
log.debug(`\u{1F4CB} MCP Config: ${JSON.stringify(mcpServers, null, 2)}`);
|
||||
const cliPath = await agent2.install();
|
||||
log.info(`Running ${agentName}...`);
|
||||
log.box(inputs.prompt, { title: "Prompt" });
|
||||
let payload;
|
||||
try {
|
||||
const parsedPrompt = JSON.parse(inputs.prompt);
|
||||
if (!("~pullfrog" in parsedPrompt)) {
|
||||
throw new Error("Invalid prompt: not a pullfrog webhook payload");
|
||||
}
|
||||
payload = parsedPrompt;
|
||||
} catch {
|
||||
payload = {
|
||||
"~pullfrog": true,
|
||||
agent: null,
|
||||
prompt: inputs.prompt,
|
||||
event: {},
|
||||
modes
|
||||
};
|
||||
}
|
||||
log.box(payload.prompt, { title: "Prompt" });
|
||||
const matchingInputKey = agent2.inputKeys.find((inputKey) => inputs[inputKey]);
|
||||
if (!matchingInputKey) {
|
||||
throwMissingApiKeyError({
|
||||
@@ -42472,7 +42417,7 @@ async function main(inputs) {
|
||||
}
|
||||
const apiKey = inputs[matchingInputKey];
|
||||
const result = await agent2.run({
|
||||
prompt: inputs.prompt,
|
||||
payload,
|
||||
mcpServers,
|
||||
githubInstallationToken,
|
||||
apiKey,
|
||||
|
||||
@@ -2,7 +2,9 @@ import { flatMorph } from "@ark/util";
|
||||
import { type } from "arktype";
|
||||
import { agents } from "./agents/index.ts";
|
||||
import { createMcpConfigs } from "./mcp/config.ts";
|
||||
import { modes } from "./modes.ts";
|
||||
import packageJson from "./package.json" with { type: "json" };
|
||||
import type { Payload } from "./payload.ts";
|
||||
import { fetchRepoSettings } from "./utils/api.ts";
|
||||
import { log } from "./utils/cli.ts";
|
||||
import {
|
||||
@@ -122,11 +124,27 @@ export async function main(inputs: Inputs): Promise<MainResult> {
|
||||
const cliPath = await agent.install();
|
||||
|
||||
log.info(`Running ${agentName}...`);
|
||||
log.box(inputs.prompt, { title: "Prompt" });
|
||||
|
||||
// TODO: check if `inputs.prompts` is JSON
|
||||
// if yes, check if it's a webhook payload or toJSON(github.event)
|
||||
// for webhook payloads, check the specified `agent` field
|
||||
let payload: Payload;
|
||||
|
||||
try {
|
||||
// attempt JSON parsing
|
||||
const parsedPrompt = JSON.parse(inputs.prompt);
|
||||
if (!("~pullfrog" in parsedPrompt)) {
|
||||
throw new Error("Invalid prompt: not a pullfrog webhook payload");
|
||||
}
|
||||
payload = parsedPrompt as Payload;
|
||||
} catch {
|
||||
payload = {
|
||||
"~pullfrog": true,
|
||||
agent: null,
|
||||
prompt: inputs.prompt,
|
||||
event: {},
|
||||
modes,
|
||||
};
|
||||
}
|
||||
|
||||
log.box(payload.prompt, { title: "Prompt" });
|
||||
|
||||
const matchingInputKey = agent.inputKeys.find((inputKey) => inputs[inputKey]);
|
||||
|
||||
@@ -142,7 +160,7 @@ export async function main(inputs: Inputs): Promise<MainResult> {
|
||||
const apiKey = inputs[matchingInputKey]!;
|
||||
|
||||
const result = await agent.run({
|
||||
prompt: inputs.prompt,
|
||||
payload,
|
||||
mcpServers,
|
||||
githubInstallationToken,
|
||||
apiKey,
|
||||
|
||||
+56
-1
@@ -97760,6 +97760,10 @@ var schema = ark.schema;
|
||||
var define2 = ark.define;
|
||||
var declare = ark.declare;
|
||||
|
||||
// mcp/shared.ts
|
||||
import { appendFileSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
|
||||
// node_modules/.pnpm/universal-user-agent@7.0.3/node_modules/universal-user-agent/index.js
|
||||
function getUserAgent() {
|
||||
if (typeof navigator === "object" && "userAgent" in navigator) {
|
||||
@@ -101412,7 +101416,58 @@ var getMcpContext = cached2(() => {
|
||||
})
|
||||
};
|
||||
});
|
||||
var tool = (tool2) => tool2;
|
||||
function getLogPath() {
|
||||
return join(process.cwd(), "log.txt");
|
||||
}
|
||||
function logToolCall({
|
||||
toolName,
|
||||
request: request2,
|
||||
error: error41,
|
||||
success
|
||||
}) {
|
||||
const logPath = getLogPath();
|
||||
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
||||
const requestStr = JSON.stringify(request2, null, 2);
|
||||
let logEntry = `[${timestamp}] Tool: ${toolName}
|
||||
Request: ${requestStr}
|
||||
`;
|
||||
if (error41) {
|
||||
const errorMessage = error41 instanceof Error ? error41.message : String(error41);
|
||||
const errorStack = error41 instanceof Error ? error41.stack : void 0;
|
||||
logEntry += `Error: ${errorMessage}
|
||||
`;
|
||||
if (errorStack) {
|
||||
logEntry += `Stack: ${errorStack}
|
||||
`;
|
||||
}
|
||||
logEntry += `Status: FAILED
|
||||
`;
|
||||
} else if (success !== void 0) {
|
||||
logEntry += `Status: ${success ? "SUCCESS" : "FAILED"}
|
||||
`;
|
||||
}
|
||||
logEntry += `${"=".repeat(80)}
|
||||
|
||||
`;
|
||||
appendFileSync(logPath, logEntry, "utf-8");
|
||||
}
|
||||
var tool = (toolDef) => {
|
||||
const toolName = toolDef.name;
|
||||
const originalExecute = toolDef.execute;
|
||||
toolDef.execute = async (args2, context) => {
|
||||
try {
|
||||
logToolCall({ toolName, request: args2 });
|
||||
const result = await originalExecute(args2, context);
|
||||
const isError = result && typeof result === "object" && "isError" in result && result.isError === true;
|
||||
logToolCall({ toolName, request: args2, success: !isError });
|
||||
return result;
|
||||
} catch (error41) {
|
||||
logToolCall({ toolName, request: args2, error: error41 });
|
||||
throw error41;
|
||||
}
|
||||
};
|
||||
return toolDef;
|
||||
};
|
||||
var addTools = (server2, tools) => {
|
||||
for (const tool2 of tools) {
|
||||
server2.addTool(tool2);
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
import { ghPullfrogMcpName } from "./mcp/index.ts";
|
||||
|
||||
export const modes = [
|
||||
export interface Mode {
|
||||
name: string;
|
||||
description: string;
|
||||
prompt: string;
|
||||
}
|
||||
|
||||
export const modes: Mode[] = [
|
||||
{
|
||||
name: "Plan",
|
||||
description:
|
||||
@@ -51,4 +57,4 @@ export const modes = [
|
||||
3. As your work progresses, update your Working Comment to share progress and results using ${ghPullfrogMcpName}/update_working_comment. Do not create additional comments unless you are explicitly asked to do so.
|
||||
4. When you finish the task, update the Working Comment a final time with a summary of the results and links to any created issues, PRs, etc.`,
|
||||
},
|
||||
] as const;
|
||||
];
|
||||
|
||||
+2
-1
@@ -24,12 +24,13 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@actions/core": "^1.11.1",
|
||||
"@actions/github": "^6.0.1",
|
||||
"@anthropic-ai/claude-agent-sdk": "0.1.37",
|
||||
"@openai/codex-sdk": "0.58.0",
|
||||
"@ark/fs": "0.53.0",
|
||||
"@ark/util": "0.53.0",
|
||||
"@octokit/rest": "^22.0.0",
|
||||
"@octokit/webhooks-types": "^7.6.1",
|
||||
"@openai/codex-sdk": "0.58.0",
|
||||
"@standard-schema/spec": "1.0.0",
|
||||
"arktype": "2.1.25",
|
||||
"dotenv": "^17.2.3",
|
||||
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/** May be a `github.event` payload that has been stringified. This case needs to be detected and handled appropriately. */
|
||||
|
||||
import type { Mode } from "./modes.ts";
|
||||
|
||||
// type Payload = GithubEventPayload | WorkflowDispatchPayload;
|
||||
// type GithubEventPayload = Record<string, any>;
|
||||
|
||||
export type Payload = {
|
||||
"~pullfrog": true;
|
||||
|
||||
/**
|
||||
* Agent slug identifier (e.g., "claude", "codex", "gemini")
|
||||
*/
|
||||
readonly agent: string | null;
|
||||
|
||||
/**
|
||||
* The prompt/instructions for the agent to execute
|
||||
*/
|
||||
readonly prompt: string;
|
||||
|
||||
/**
|
||||
* Event data from webhook payload.
|
||||
*/
|
||||
readonly event: object;
|
||||
|
||||
/**
|
||||
* Execution mode configuration
|
||||
*/
|
||||
modes: readonly Mode[];
|
||||
|
||||
/**
|
||||
* Optional IDs of the issue, PR, or comment that the agent is working on
|
||||
*/
|
||||
readonly comment_id?: number | null;
|
||||
readonly issue_id?: number | null;
|
||||
readonly pr_id?: number | null;
|
||||
};
|
||||
Generated
+137
@@ -11,6 +11,9 @@ importers:
|
||||
'@actions/core':
|
||||
specifier: ^1.11.1
|
||||
version: 1.11.1
|
||||
'@actions/github':
|
||||
specifier: ^6.0.1
|
||||
version: 6.0.1
|
||||
'@anthropic-ai/claude-agent-sdk':
|
||||
specifier: 0.1.37
|
||||
version: 0.1.37(zod@3.25.76)
|
||||
@@ -75,6 +78,9 @@ packages:
|
||||
'@actions/exec@1.1.1':
|
||||
resolution: {integrity: sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w==}
|
||||
|
||||
'@actions/github@6.0.1':
|
||||
resolution: {integrity: sha512-xbZVcaqD4XnQAe35qSQqskb3SqIAfRyLBrHMd/8TuL7hJSz2QtbDwnNM8zWx4zO5l2fnGtseNE3MbEvD7BxVMw==}
|
||||
|
||||
'@actions/http-client@2.2.3':
|
||||
resolution: {integrity: sha512-mx8hyJi/hjFvbPokCg4uRd4ZX78t+YyRPtnKWwIl+RzNaVuFpQHfmlGVfsKEJN8LwTCvL+DfVgAM04XaHkm6bA==}
|
||||
|
||||
@@ -324,10 +330,18 @@ packages:
|
||||
resolution: {integrity: sha512-kOQ4+fHuT4KbR2iq2IjeV32HiihueuOf1vJkq18z08CLZ1UQrTc8BXJpVfxZkq45+inLLD+D4xx4nBjUelJa4Q==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
'@octokit/auth-token@4.0.0':
|
||||
resolution: {integrity: sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA==}
|
||||
engines: {node: '>= 18'}
|
||||
|
||||
'@octokit/auth-token@6.0.0':
|
||||
resolution: {integrity: sha512-P4YJBPdPSpWTQ1NU4XYdvHvXJJDxM6YwpS0FZHRgP7YFkdVxsWcpWGy/NVqlAA7PcPCnMacXlRm1y2PFZRWL/w==}
|
||||
engines: {node: '>= 20'}
|
||||
|
||||
'@octokit/core@5.2.2':
|
||||
resolution: {integrity: sha512-/g2d4sW9nUDJOMz3mabVQvOGhVa4e/BN/Um7yca9Bb2XTzPPnfTWHWQg+IsEYO7M3Vx+EXvaM/I2pJWIMun1bg==}
|
||||
engines: {node: '>= 18'}
|
||||
|
||||
'@octokit/core@7.0.5':
|
||||
resolution: {integrity: sha512-t54CUOsFMappY1Jbzb7fetWeO0n6K0k/4+/ZpkS+3Joz8I4VcvY9OiEBFRYISqaI2fq5sCiPtAjRDOzVYG8m+Q==}
|
||||
engines: {node: '>= 20'}
|
||||
@@ -336,10 +350,24 @@ packages:
|
||||
resolution: {integrity: sha512-7P1dRAZxuWAOPI7kXfio88trNi/MegQ0IJD3vfgC3b+LZo1Qe6gRJc2v0mz2USWWJOKrB2h5spXCzGbw+fAdqA==}
|
||||
engines: {node: '>= 20'}
|
||||
|
||||
'@octokit/endpoint@9.0.6':
|
||||
resolution: {integrity: sha512-H1fNTMA57HbkFESSt3Y9+FBICv+0jFceJFPWDePYlR/iMGrwM5ph+Dd4XRQs+8X+PUFURLQgX9ChPfhJ/1uNQw==}
|
||||
engines: {node: '>= 18'}
|
||||
|
||||
'@octokit/graphql@7.1.1':
|
||||
resolution: {integrity: sha512-3mkDltSfcDUoa176nlGoA32RGjeWjl3K7F/BwHwRMJUW/IteSa4bnSV8p2ThNkcIcZU2umkZWxwETSSCJf2Q7g==}
|
||||
engines: {node: '>= 18'}
|
||||
|
||||
'@octokit/graphql@9.0.2':
|
||||
resolution: {integrity: sha512-iz6KzZ7u95Fzy9Nt2L8cG88lGRMr/qy1Q36ih/XVzMIlPDMYwaNLE/ENhqmIzgPrlNWiYJkwmveEetvxAgFBJw==}
|
||||
engines: {node: '>= 20'}
|
||||
|
||||
'@octokit/openapi-types@20.0.0':
|
||||
resolution: {integrity: sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA==}
|
||||
|
||||
'@octokit/openapi-types@24.2.0':
|
||||
resolution: {integrity: sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==}
|
||||
|
||||
'@octokit/openapi-types@26.0.0':
|
||||
resolution: {integrity: sha512-7AtcfKtpo77j7Ts73b4OWhOZHTKo/gGY8bB3bNBQz4H+GRSWqx2yvj8TXRsbdTE0eRmYmXOEY66jM7mJ7LzfsA==}
|
||||
|
||||
@@ -349,18 +377,34 @@ packages:
|
||||
peerDependencies:
|
||||
'@octokit/core': '>=6'
|
||||
|
||||
'@octokit/plugin-paginate-rest@9.2.2':
|
||||
resolution: {integrity: sha512-u3KYkGF7GcZnSD/3UP0S7K5XUFT2FkOQdcfXZGZQPGv3lm4F2Xbf71lvjldr8c1H3nNbF+33cLEkWYbokGWqiQ==}
|
||||
engines: {node: '>= 18'}
|
||||
peerDependencies:
|
||||
'@octokit/core': '5'
|
||||
|
||||
'@octokit/plugin-request-log@6.0.0':
|
||||
resolution: {integrity: sha512-UkOzeEN3W91/eBq9sPZNQ7sUBvYCqYbrrD8gTbBuGtHEuycE4/awMXcYvx6sVYo7LypPhmQwwpUe4Yyu4QZN5Q==}
|
||||
engines: {node: '>= 20'}
|
||||
peerDependencies:
|
||||
'@octokit/core': '>=6'
|
||||
|
||||
'@octokit/plugin-rest-endpoint-methods@10.4.1':
|
||||
resolution: {integrity: sha512-xV1b+ceKV9KytQe3zCVqjg+8GTGfDYwaT1ATU5isiUyVtlVAO3HNdzpS4sr4GBx4hxQ46s7ITtZrAsxG22+rVg==}
|
||||
engines: {node: '>= 18'}
|
||||
peerDependencies:
|
||||
'@octokit/core': '5'
|
||||
|
||||
'@octokit/plugin-rest-endpoint-methods@16.1.0':
|
||||
resolution: {integrity: sha512-nCsyiKoGRnhH5LkH8hJEZb9swpqOcsW+VXv1QoyUNQXJeVODG4+xM6UICEqyqe9XFr6LkL8BIiFCPev8zMDXPw==}
|
||||
engines: {node: '>= 20'}
|
||||
peerDependencies:
|
||||
'@octokit/core': '>=6'
|
||||
|
||||
'@octokit/request-error@5.1.1':
|
||||
resolution: {integrity: sha512-v9iyEQJH6ZntoENr9/yXxjuezh4My67CBSu9r6Ve/05Iu5gNgnisNWOsoJHTP6k0Rr0+HQIpnH+kyammu90q/g==}
|
||||
engines: {node: '>= 18'}
|
||||
|
||||
'@octokit/request-error@7.0.1':
|
||||
resolution: {integrity: sha512-CZpFwV4+1uBrxu7Cw8E5NCXDWFNf18MSY23TdxCBgjw1tXXHvTrZVsXlW8hgFTOLw8RQR1BBrMvYRtuyaijHMA==}
|
||||
engines: {node: '>= 20'}
|
||||
@@ -369,10 +413,20 @@ packages:
|
||||
resolution: {integrity: sha512-TXnouHIYLtgDhKo+N6mXATnDBkV05VwbR0TtMWpgTHIoQdRQfCSzmy/LGqR1AbRMbijq/EckC/E3/ZNcU92NaQ==}
|
||||
engines: {node: '>= 20'}
|
||||
|
||||
'@octokit/request@8.4.1':
|
||||
resolution: {integrity: sha512-qnB2+SY3hkCmBxZsR/MPCybNmbJe4KAlfWErXq+rBKkQJlbjdJeS85VI9r8UqeLYLvnAenU8Q1okM/0MBsAGXw==}
|
||||
engines: {node: '>= 18'}
|
||||
|
||||
'@octokit/rest@22.0.0':
|
||||
resolution: {integrity: sha512-z6tmTu9BTnw51jYGulxrlernpsQYXpui1RK21vmXn8yF5bp6iX16yfTtJYGK5Mh1qDkvDOmp2n8sRMcQmR8jiA==}
|
||||
engines: {node: '>= 20'}
|
||||
|
||||
'@octokit/types@12.6.0':
|
||||
resolution: {integrity: sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw==}
|
||||
|
||||
'@octokit/types@13.10.0':
|
||||
resolution: {integrity: sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==}
|
||||
|
||||
'@octokit/types@15.0.0':
|
||||
resolution: {integrity: sha512-8o6yDfmoGJUIeR9OfYU0/TUJTnMPG2r68+1yEdUeG2Fdqpj8Qetg0ziKIgcBm0RW/j29H41WP37CYCEhp6GoHQ==}
|
||||
|
||||
@@ -442,6 +496,9 @@ packages:
|
||||
resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
before-after-hook@2.2.3:
|
||||
resolution: {integrity: sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==}
|
||||
|
||||
before-after-hook@4.0.0:
|
||||
resolution: {integrity: sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ==}
|
||||
|
||||
@@ -509,6 +566,9 @@ packages:
|
||||
resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==}
|
||||
engines: {node: '>= 0.8'}
|
||||
|
||||
deprecation@2.3.1:
|
||||
resolution: {integrity: sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==}
|
||||
|
||||
dotenv@17.2.3:
|
||||
resolution: {integrity: sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==}
|
||||
engines: {node: '>=12'}
|
||||
@@ -953,6 +1013,9 @@ packages:
|
||||
resolution: {integrity: sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
universal-user-agent@6.0.1:
|
||||
resolution: {integrity: sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ==}
|
||||
|
||||
universal-user-agent@7.0.3:
|
||||
resolution: {integrity: sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A==}
|
||||
|
||||
@@ -1040,6 +1103,16 @@ snapshots:
|
||||
dependencies:
|
||||
'@actions/io': 1.1.3
|
||||
|
||||
'@actions/github@6.0.1':
|
||||
dependencies:
|
||||
'@actions/http-client': 2.2.3
|
||||
'@octokit/core': 5.2.2
|
||||
'@octokit/plugin-paginate-rest': 9.2.2(@octokit/core@5.2.2)
|
||||
'@octokit/plugin-rest-endpoint-methods': 10.4.1(@octokit/core@5.2.2)
|
||||
'@octokit/request': 8.4.1
|
||||
'@octokit/request-error': 5.1.1
|
||||
undici: 5.29.0
|
||||
|
||||
'@actions/http-client@2.2.3':
|
||||
dependencies:
|
||||
tunnel: 0.0.6
|
||||
@@ -1208,8 +1281,20 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@octokit/auth-token@4.0.0': {}
|
||||
|
||||
'@octokit/auth-token@6.0.0': {}
|
||||
|
||||
'@octokit/core@5.2.2':
|
||||
dependencies:
|
||||
'@octokit/auth-token': 4.0.0
|
||||
'@octokit/graphql': 7.1.1
|
||||
'@octokit/request': 8.4.1
|
||||
'@octokit/request-error': 5.1.1
|
||||
'@octokit/types': 13.10.0
|
||||
before-after-hook: 2.2.3
|
||||
universal-user-agent: 6.0.1
|
||||
|
||||
'@octokit/core@7.0.5':
|
||||
dependencies:
|
||||
'@octokit/auth-token': 6.0.0
|
||||
@@ -1225,12 +1310,27 @@ snapshots:
|
||||
'@octokit/types': 15.0.0
|
||||
universal-user-agent: 7.0.3
|
||||
|
||||
'@octokit/endpoint@9.0.6':
|
||||
dependencies:
|
||||
'@octokit/types': 13.10.0
|
||||
universal-user-agent: 6.0.1
|
||||
|
||||
'@octokit/graphql@7.1.1':
|
||||
dependencies:
|
||||
'@octokit/request': 8.4.1
|
||||
'@octokit/types': 13.10.0
|
||||
universal-user-agent: 6.0.1
|
||||
|
||||
'@octokit/graphql@9.0.2':
|
||||
dependencies:
|
||||
'@octokit/request': 10.0.5
|
||||
'@octokit/types': 15.0.0
|
||||
universal-user-agent: 7.0.3
|
||||
|
||||
'@octokit/openapi-types@20.0.0': {}
|
||||
|
||||
'@octokit/openapi-types@24.2.0': {}
|
||||
|
||||
'@octokit/openapi-types@26.0.0': {}
|
||||
|
||||
'@octokit/plugin-paginate-rest@13.2.0(@octokit/core@7.0.5)':
|
||||
@@ -1238,15 +1338,31 @@ snapshots:
|
||||
'@octokit/core': 7.0.5
|
||||
'@octokit/types': 15.0.0
|
||||
|
||||
'@octokit/plugin-paginate-rest@9.2.2(@octokit/core@5.2.2)':
|
||||
dependencies:
|
||||
'@octokit/core': 5.2.2
|
||||
'@octokit/types': 12.6.0
|
||||
|
||||
'@octokit/plugin-request-log@6.0.0(@octokit/core@7.0.5)':
|
||||
dependencies:
|
||||
'@octokit/core': 7.0.5
|
||||
|
||||
'@octokit/plugin-rest-endpoint-methods@10.4.1(@octokit/core@5.2.2)':
|
||||
dependencies:
|
||||
'@octokit/core': 5.2.2
|
||||
'@octokit/types': 12.6.0
|
||||
|
||||
'@octokit/plugin-rest-endpoint-methods@16.1.0(@octokit/core@7.0.5)':
|
||||
dependencies:
|
||||
'@octokit/core': 7.0.5
|
||||
'@octokit/types': 15.0.0
|
||||
|
||||
'@octokit/request-error@5.1.1':
|
||||
dependencies:
|
||||
'@octokit/types': 13.10.0
|
||||
deprecation: 2.3.1
|
||||
once: 1.4.0
|
||||
|
||||
'@octokit/request-error@7.0.1':
|
||||
dependencies:
|
||||
'@octokit/types': 15.0.0
|
||||
@@ -1259,6 +1375,13 @@ snapshots:
|
||||
fast-content-type-parse: 3.0.0
|
||||
universal-user-agent: 7.0.3
|
||||
|
||||
'@octokit/request@8.4.1':
|
||||
dependencies:
|
||||
'@octokit/endpoint': 9.0.6
|
||||
'@octokit/request-error': 5.1.1
|
||||
'@octokit/types': 13.10.0
|
||||
universal-user-agent: 6.0.1
|
||||
|
||||
'@octokit/rest@22.0.0':
|
||||
dependencies:
|
||||
'@octokit/core': 7.0.5
|
||||
@@ -1266,6 +1389,14 @@ snapshots:
|
||||
'@octokit/plugin-request-log': 6.0.0(@octokit/core@7.0.5)
|
||||
'@octokit/plugin-rest-endpoint-methods': 16.1.0(@octokit/core@7.0.5)
|
||||
|
||||
'@octokit/types@12.6.0':
|
||||
dependencies:
|
||||
'@octokit/openapi-types': 20.0.0
|
||||
|
||||
'@octokit/types@13.10.0':
|
||||
dependencies:
|
||||
'@octokit/openapi-types': 24.2.0
|
||||
|
||||
'@octokit/types@15.0.0':
|
||||
dependencies:
|
||||
'@octokit/openapi-types': 26.0.0
|
||||
@@ -1337,6 +1468,8 @@ snapshots:
|
||||
|
||||
astral-regex@2.0.0: {}
|
||||
|
||||
before-after-hook@2.2.3: {}
|
||||
|
||||
before-after-hook@4.0.0: {}
|
||||
|
||||
body-parser@2.2.0:
|
||||
@@ -1404,6 +1537,8 @@ snapshots:
|
||||
|
||||
depd@2.0.0: {}
|
||||
|
||||
deprecation@2.3.1: {}
|
||||
|
||||
dotenv@17.2.3: {}
|
||||
|
||||
dunder-proto@1.0.1:
|
||||
@@ -1889,6 +2024,8 @@ snapshots:
|
||||
|
||||
unicorn-magic@0.3.0: {}
|
||||
|
||||
universal-user-agent@6.0.1: {}
|
||||
|
||||
universal-user-agent@7.0.3: {}
|
||||
|
||||
unpipe@1.0.0: {}
|
||||
|
||||
Reference in New Issue
Block a user