centralize env management via createAgentEnv
This commit is contained in:
+2
-2
@@ -2,7 +2,7 @@ import { query, type SDKMessage } from "@anthropic-ai/claude-agent-sdk";
|
||||
import packageJson from "../package.json" with { type: "json" };
|
||||
import { log } from "../utils/cli.ts";
|
||||
import { addInstructions } from "./instructions.ts";
|
||||
import { agent, installFromNpmTarball } from "./shared.ts";
|
||||
import { agent, installFromNpmTarball, setupProcessAgentEnv } from "./shared.ts";
|
||||
|
||||
export const claude = agent({
|
||||
name: "claude",
|
||||
@@ -15,7 +15,7 @@ export const claude = agent({
|
||||
});
|
||||
},
|
||||
run: async ({ payload, mcpServers, apiKey, cliPath }) => {
|
||||
process.env.ANTHROPIC_API_KEY = apiKey;
|
||||
setupProcessAgentEnv({ ANTHROPIC_API_KEY: apiKey });
|
||||
|
||||
const prompt = addInstructions(payload);
|
||||
console.log(prompt);
|
||||
|
||||
+11
-13
@@ -4,7 +4,12 @@ import { join } from "node:path";
|
||||
import { Codex, type CodexOptions, type ThreadEvent } from "@openai/codex-sdk";
|
||||
import { log } from "../utils/cli.ts";
|
||||
import { addInstructions } from "./instructions.ts";
|
||||
import { agent, type ConfigureMcpServersParams, installFromNpmTarball } from "./shared.ts";
|
||||
import {
|
||||
agent,
|
||||
type ConfigureMcpServersParams,
|
||||
installFromNpmTarball,
|
||||
setupProcessAgentEnv,
|
||||
} from "./shared.ts";
|
||||
|
||||
export const codex = agent({
|
||||
name: "codex",
|
||||
@@ -15,16 +20,16 @@ export const codex = agent({
|
||||
executablePath: "bin/codex.js",
|
||||
});
|
||||
},
|
||||
run: async ({ payload, mcpServers, apiKey, cliPath, githubInstallationToken }) => {
|
||||
process.env.OPENAI_API_KEY = apiKey;
|
||||
process.env.GITHUB_INSTALLATION_TOKEN = githubInstallationToken;
|
||||
|
||||
run: async ({ payload, mcpServers, apiKey, cliPath }) => {
|
||||
// create config directory for codex before setting HOME
|
||||
const tempHome = process.env.PULLFROG_TEMP_DIR!;
|
||||
const configDir = join(tempHome, ".config", "codex");
|
||||
mkdirSync(configDir, { recursive: true });
|
||||
|
||||
process.env.HOME = tempHome;
|
||||
setupProcessAgentEnv({
|
||||
OPENAI_API_KEY: apiKey,
|
||||
HOME: tempHome,
|
||||
});
|
||||
|
||||
configureCodexMcpServers({ mcpServers, cliPath });
|
||||
|
||||
@@ -35,10 +40,6 @@ export const codex = agent({
|
||||
};
|
||||
|
||||
const codex = new Codex(codexOptions);
|
||||
// Configure thread options to match Claude's permissions (bypassPermissions)
|
||||
// approvalPolicy: "never" = no approval needed (equivalent to bypassPermissions)
|
||||
// sandboxMode: "workspace-write" = allow file writes
|
||||
// networkAccessEnabled: true = allow network access (needed for GitHub API calls)
|
||||
const thread = codex.startThread({
|
||||
approvalPolicy: "never",
|
||||
sandboxMode: "workspace-write",
|
||||
@@ -46,10 +47,8 @@ export const codex = agent({
|
||||
});
|
||||
|
||||
try {
|
||||
// Use runStreamed to get streaming events similar to claude.ts
|
||||
const streamedTurn = await thread.runStreamed(addInstructions(payload));
|
||||
|
||||
// Stream events and handle them
|
||||
let finalOutput = "";
|
||||
for await (const event of streamedTurn.events) {
|
||||
const handler = messageHandlers[event.type];
|
||||
@@ -58,7 +57,6 @@ export const codex = agent({
|
||||
handler(event as never);
|
||||
}
|
||||
|
||||
// Capture final response from agent messages
|
||||
if (event.type === "item.completed" && event.item.type === "agent_message") {
|
||||
finalOutput = event.item.text;
|
||||
}
|
||||
|
||||
+9
-14
@@ -4,7 +4,12 @@ import { homedir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import { log } from "../utils/cli.ts";
|
||||
import { addInstructions } from "./instructions.ts";
|
||||
import { agent, type ConfigureMcpServersParams, installFromCurl } from "./shared.ts";
|
||||
import {
|
||||
agent,
|
||||
type ConfigureMcpServersParams,
|
||||
createAgentEnv,
|
||||
installFromCurl,
|
||||
} from "./shared.ts";
|
||||
|
||||
// cursor cli event types inferred from stream-json output
|
||||
interface CursorSystemEvent {
|
||||
@@ -138,10 +143,7 @@ export const cursor = agent({
|
||||
executableName: "cursor-agent",
|
||||
});
|
||||
},
|
||||
run: async ({ payload, apiKey, cliPath, githubInstallationToken, mcpServers }) => {
|
||||
process.env.CURSOR_API_KEY = apiKey;
|
||||
process.env.GITHUB_INSTALLATION_TOKEN = githubInstallationToken;
|
||||
|
||||
run: async ({ payload, apiKey, cliPath, mcpServers }) => {
|
||||
configureCursorMcpServers({ mcpServers, cliPath });
|
||||
|
||||
try {
|
||||
@@ -165,16 +167,9 @@ export const cursor = agent({
|
||||
],
|
||||
{
|
||||
cwd: process.cwd(),
|
||||
env: {
|
||||
env: createAgentEnv({
|
||||
CURSOR_API_KEY: apiKey,
|
||||
GITHUB_INSTALLATION_TOKEN: githubInstallationToken,
|
||||
LOG_LEVEL: process.env.LOG_LEVEL,
|
||||
NODE_ENV: process.env.NODE_ENV,
|
||||
HOME: process.env.HOME,
|
||||
PATH: process.env.PATH,
|
||||
// Don't override HOME - Cursor CLI needs access to macOS keychain
|
||||
// MCP config is written to tempDir/.cursor/mcp.json which Cursor will find
|
||||
},
|
||||
}),
|
||||
stdio: ["ignore", "pipe", "pipe"], // Ignore stdin, pipe stdout/stderr
|
||||
}
|
||||
);
|
||||
|
||||
+9
-14
@@ -2,7 +2,12 @@ import { spawnSync } from "node:child_process";
|
||||
import { log } from "../utils/cli.ts";
|
||||
import { spawn } from "../utils/subprocess.ts";
|
||||
import { addInstructions } from "./instructions.ts";
|
||||
import { agent, type ConfigureMcpServersParams, installFromGithub } from "./shared.ts";
|
||||
import {
|
||||
agent,
|
||||
type ConfigureMcpServersParams,
|
||||
createAgentEnv,
|
||||
installFromGithub,
|
||||
} from "./shared.ts";
|
||||
|
||||
// gemini cli event types inferred from stream-json output (NDJSON format)
|
||||
interface GeminiInitEvent {
|
||||
@@ -152,16 +157,12 @@ export const gemini = agent({
|
||||
assetName: "gemini.js",
|
||||
});
|
||||
},
|
||||
run: async ({ payload, apiKey, mcpServers, githubInstallationToken, cliPath }) => {
|
||||
run: async ({ payload, apiKey, mcpServers, cliPath }) => {
|
||||
configureGeminiMcpServers({ mcpServers, cliPath });
|
||||
if (!apiKey) {
|
||||
throw new Error("google_api_key or gemini_api_key is required for gemini agent");
|
||||
}
|
||||
|
||||
// Set environment variables for Gemini CLI and MCP servers
|
||||
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)}...`);
|
||||
|
||||
@@ -170,15 +171,9 @@ export const gemini = agent({
|
||||
const result = await spawn({
|
||||
cmd: "node",
|
||||
args: [cliPath, "--yolo", "--output-format=stream-json", "-p", sessionPrompt],
|
||||
env: {
|
||||
PATH: process.env.PATH || "",
|
||||
HOME: process.env.HOME || "",
|
||||
TMPDIR: process.env.TMPDIR || "/tmp",
|
||||
env: createAgentEnv({
|
||||
GEMINI_API_KEY: apiKey,
|
||||
GITHUB_INSTALLATION_TOKEN: githubInstallationToken,
|
||||
LOG_LEVEL: process.env.LOG_LEVEL!,
|
||||
NODE_ENV: process.env.NODE_ENV!,
|
||||
},
|
||||
}),
|
||||
timeout: 600000, // 10 minutes
|
||||
onStdout: async (chunk) => {
|
||||
const text = chunk.toString();
|
||||
|
||||
+35
-9
@@ -8,6 +8,7 @@ import type { McpHttpServerConfig } from "@anthropic-ai/claude-agent-sdk";
|
||||
import type { show } from "@ark/util";
|
||||
import { type AgentManifest, type AgentName, agentsManifest, type Payload } from "../external.ts";
|
||||
import { log } from "../utils/cli.ts";
|
||||
import { getGitHubInstallationToken } from "../utils/github.ts";
|
||||
|
||||
/**
|
||||
* Result returned by agent execution
|
||||
@@ -24,7 +25,6 @@ export interface AgentResult {
|
||||
*/
|
||||
export interface AgentConfig {
|
||||
apiKey: string;
|
||||
githubInstallationToken: string;
|
||||
payload: Payload;
|
||||
mcpServers: Record<string, McpHttpServerConfig>;
|
||||
cliPath: string;
|
||||
@@ -38,6 +38,35 @@ export interface ConfigureMcpServersParams {
|
||||
cliPath: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add agent-specific vars to a whitelisted environment object for agent subprocesses.
|
||||
*
|
||||
* @param agentSpecificVars - Object containing agent-specific environment variables to include
|
||||
* @returns Whitelisted environment object safe for subprocess spawning
|
||||
*/
|
||||
export function createAgentEnv(agentSpecificVars: Record<string, string>): Record<string, string> {
|
||||
return {
|
||||
PATH: process.env.PATH,
|
||||
HOME: process.env.HOME,
|
||||
LOG_LEVEL: process.env.LOG_LEVEL,
|
||||
NODE_ENV: process.env.NODE_ENV,
|
||||
GITHUB_TOKEN: getGitHubInstallationToken(),
|
||||
...agentSpecificVars,
|
||||
// values could be undefined but will be ignored
|
||||
} as never;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up whitelisted environment variables in the current process.
|
||||
* Used for SDKs that run in the same process (e.g., Claude SDK, Codex SDK).
|
||||
* Includes agent-agnostic vars (PATH, HOME, LOG_LEVEL, NODE_ENV) plus agent-specific vars.
|
||||
*
|
||||
* @param agentSpecificVars - Object containing agent-specific environment variables to include
|
||||
*/
|
||||
export function setupProcessAgentEnv(agentSpecificVars: Record<string, string>): void {
|
||||
Object.assign(process.env, createAgentEnv(agentSpecificVars));
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameters for installing from npm tarball
|
||||
*/
|
||||
@@ -296,17 +325,14 @@ export async function installFromCurl({
|
||||
|
||||
log.info(`Installing to temp directory at ${tempDir}...`);
|
||||
|
||||
// Run the install script with HOME set to temp directory
|
||||
// The Cursor install script installs to $HOME/.local/bin/{executableName}
|
||||
// By setting HOME=tempDir, we ensure it installs to tempDir/.local/bin/{executableName}
|
||||
const installResult = spawnSync("bash", [installScriptPath], {
|
||||
cwd: tempDir,
|
||||
env: {
|
||||
HOME: tempDir, // Cursor install script uses HOME for installation path
|
||||
PATH: process.env.PATH || "",
|
||||
SHELL: process.env.SHELL || "/bin/bash",
|
||||
USER: process.env.USER || "",
|
||||
TMPDIR: process.env.TMPDIR || "/tmp",
|
||||
// Run the install script with HOME set to temp directory
|
||||
// ensuring a fresh install for each run
|
||||
HOME: tempDir,
|
||||
SHELL: process.env.SHELL,
|
||||
USER: process.env.USER,
|
||||
},
|
||||
stdio: "pipe",
|
||||
encoding: "utf-8",
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { existsSync, readFileSync } from "node:fs";
|
||||
import { mkdtemp, writeFile } from "node:fs/promises";
|
||||
import { mkdtemp } from "node:fs/promises";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import { flatMorph } from "@ark/util";
|
||||
@@ -18,7 +17,7 @@ import { log } from "./utils/cli.ts";
|
||||
import {
|
||||
parseRepoContext,
|
||||
type RepoContext,
|
||||
revokeInstallationToken,
|
||||
revokeGitHubInstallationToken,
|
||||
setupGitHubInstallationToken,
|
||||
} from "./utils/github.ts";
|
||||
import { setupGitAuth, setupGitBranch, setupGitConfig } from "./utils/setup.ts";
|
||||
@@ -49,9 +48,7 @@ export interface MainResult {
|
||||
}
|
||||
|
||||
export async function main(inputs: Inputs): Promise<MainResult> {
|
||||
let pollInterval: NodeJS.Timeout | null = null;
|
||||
let mcpServerClose: (() => Promise<void>) | undefined;
|
||||
let githubInstallationToken: string | undefined;
|
||||
|
||||
try {
|
||||
// parse payload early to extract agent
|
||||
@@ -59,15 +56,12 @@ export async function main(inputs: Inputs): Promise<MainResult> {
|
||||
|
||||
const partialCtx = await initializeContext(inputs, payload);
|
||||
const ctx = partialCtx as MainContext;
|
||||
githubInstallationToken = ctx.githubInstallationToken;
|
||||
|
||||
setupGitAuth({
|
||||
githubInstallationToken: ctx.githubInstallationToken,
|
||||
repoContext: ctx.repoContext,
|
||||
});
|
||||
await setupTempDirectory(ctx);
|
||||
setupMcpLogPolling(ctx);
|
||||
pollInterval = ctx.pollInterval;
|
||||
|
||||
setupGitBranch(ctx.payload);
|
||||
await startMcpServer(ctx);
|
||||
@@ -87,15 +81,10 @@ export async function main(inputs: Inputs): Promise<MainResult> {
|
||||
error: errorMessage,
|
||||
};
|
||||
} finally {
|
||||
if (pollInterval) {
|
||||
clearInterval(pollInterval);
|
||||
}
|
||||
if (mcpServerClose) {
|
||||
await mcpServerClose();
|
||||
}
|
||||
if (githubInstallationToken) {
|
||||
await revokeInstallationToken(githubInstallationToken);
|
||||
}
|
||||
await revokeGitHubInstallationToken();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,8 +159,6 @@ interface MainContext {
|
||||
agentName: AgentNameType;
|
||||
agent: (typeof agents)[AgentNameType];
|
||||
sharedTempDir: string;
|
||||
mcpLogPath: string;
|
||||
pollInterval: NodeJS.Timeout | null;
|
||||
payload: Payload;
|
||||
mcpServerUrl: string;
|
||||
mcpServerClose: () => Promise<void>;
|
||||
@@ -210,8 +197,6 @@ async function initializeContext(
|
||||
agent,
|
||||
payload: resolvedPayload,
|
||||
sharedTempDir: "",
|
||||
mcpLogPath: "",
|
||||
pollInterval: null,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -262,25 +247,9 @@ async function setupTempDirectory(
|
||||
): Promise<void> {
|
||||
ctx.sharedTempDir = await mkdtemp(join(tmpdir(), "pullfrog-"));
|
||||
process.env.PULLFROG_TEMP_DIR = ctx.sharedTempDir;
|
||||
ctx.mcpLogPath = join(ctx.sharedTempDir, "mcpLog.txt");
|
||||
await writeFile(ctx.mcpLogPath, "", "utf-8");
|
||||
log.info(`📂 PULLFROG_TEMP_DIR has been created at ${ctx.sharedTempDir}`);
|
||||
}
|
||||
|
||||
function setupMcpLogPolling(ctx: MainContext): void {
|
||||
let lastSize = 0;
|
||||
ctx.pollInterval = setInterval(() => {
|
||||
if (existsSync(ctx.mcpLogPath)) {
|
||||
const content = readFileSync(ctx.mcpLogPath, "utf-8");
|
||||
if (content.length > lastSize) {
|
||||
const newContent = content.slice(lastSize);
|
||||
process.stdout.write(newContent);
|
||||
lastSize = content.length;
|
||||
}
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
|
||||
function parsePayload(inputs: Inputs): Payload {
|
||||
try {
|
||||
const parsedPrompt = JSON.parse(inputs.prompt);
|
||||
@@ -307,7 +276,6 @@ async function startMcpServer(ctx: MainContext): Promise<void> {
|
||||
const githubRepository = `${repoContext.owner}/${repoContext.name}`;
|
||||
const allModes = [...modes, ...(ctx.payload.modes || [])];
|
||||
|
||||
process.env.GITHUB_INSTALLATION_TOKEN = ctx.githubInstallationToken;
|
||||
process.env.GITHUB_REPOSITORY = githubRepository;
|
||||
process.env.PULLFROG_MODES = JSON.stringify(allModes);
|
||||
process.env.PULLFROG_PAYLOAD = JSON.stringify(ctx.payload);
|
||||
@@ -352,7 +320,6 @@ async function runAgent(ctx: MainContext): Promise<AgentResult> {
|
||||
return ctx.agent.run({
|
||||
payload: ctx.payload,
|
||||
mcpServers: ctx.mcpServers,
|
||||
githubInstallationToken: ctx.githubInstallationToken,
|
||||
apiKey: ctx.apiKey,
|
||||
cliPath: ctx.cliPath,
|
||||
});
|
||||
|
||||
+7
-10
@@ -2,7 +2,7 @@ import { Octokit } from "@octokit/rest";
|
||||
import type { StandardSchemaV1 } from "@standard-schema/spec";
|
||||
import type { FastMCP, Tool } from "fastmcp";
|
||||
import type { Payload } from "../external.ts";
|
||||
import { parseRepoContext, type RepoContext } from "../utils/github.ts";
|
||||
import { getGitHubInstallationToken, parseRepoContext, type RepoContext } from "../utils/github.ts";
|
||||
|
||||
export interface ToolResult {
|
||||
content: {
|
||||
@@ -28,15 +28,10 @@ export function getPayload(): Payload {
|
||||
}
|
||||
|
||||
export function getMcpContext(): McpContext {
|
||||
const githubInstallationToken = process.env.GITHUB_INSTALLATION_TOKEN;
|
||||
if (!githubInstallationToken) {
|
||||
throw new Error("GITHUB_INSTALLATION_TOKEN environment variable is required");
|
||||
}
|
||||
|
||||
return {
|
||||
...parseRepoContext(),
|
||||
octokit: new Octokit({
|
||||
auth: githubInstallationToken,
|
||||
auth: getGitHubInstallationToken(),
|
||||
}),
|
||||
payload: getPayload(),
|
||||
};
|
||||
@@ -56,9 +51,10 @@ export const addTools = (server: FastMCP, tools: Tool<any, any>[]) => {
|
||||
return server;
|
||||
};
|
||||
|
||||
export const contextualize =
|
||||
<T>(executor: (params: T, ctx: McpContext) => Promise<Record<string, any>>) =>
|
||||
async (params: T): Promise<ToolResult> => {
|
||||
export const contextualize = <T>(
|
||||
executor: (params: T, ctx: McpContext) => Promise<Record<string, any>>
|
||||
) => {
|
||||
return async (params: T): Promise<ToolResult> => {
|
||||
try {
|
||||
const ctx = getMcpContext();
|
||||
const result = await executor(params, ctx);
|
||||
@@ -67,6 +63,7 @@ export const contextualize =
|
||||
return handleToolError(error);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
const handleToolSuccess = (data: Record<string, any>): ToolResult => {
|
||||
return {
|
||||
|
||||
+1
-88
@@ -3,8 +3,7 @@
|
||||
*/
|
||||
|
||||
import { spawnSync } from "node:child_process";
|
||||
import { appendFileSync, existsSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
import { existsSync } from "node:fs";
|
||||
import * as core from "@actions/core";
|
||||
import { table } from "table";
|
||||
|
||||
@@ -325,41 +324,8 @@ export const log = {
|
||||
|
||||
log.info(output.trimEnd());
|
||||
},
|
||||
|
||||
/**
|
||||
* Log MCP tool call information to mcpLog.txt in the temp directory
|
||||
*/
|
||||
toolCallToFile: ({
|
||||
toolName,
|
||||
request,
|
||||
result,
|
||||
error,
|
||||
}: {
|
||||
toolName: string;
|
||||
request: unknown;
|
||||
result?: string;
|
||||
error?: string;
|
||||
}): void => {
|
||||
const logPath = getMcpLogPath();
|
||||
const params: Parameters<typeof formatToolCall>[0] = { toolName, request };
|
||||
if (error) {
|
||||
params.error = error;
|
||||
} else if (result) {
|
||||
params.result = result;
|
||||
}
|
||||
const logEntry = formatToolCall(params);
|
||||
appendFileSync(logPath, logEntry, "utf-8");
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the path to the MCP log file in the temp directory
|
||||
*/
|
||||
function getMcpLogPath(): string {
|
||||
const tempDir = process.env.PULLFROG_TEMP_DIR!;
|
||||
return join(tempDir, "mcpLog.txt");
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a value as JSON, using compact format for simple values and pretty-printed for complex ones
|
||||
*/
|
||||
@@ -385,59 +351,6 @@ export function formatIndentedField(label: string, content: string): string {
|
||||
return formatted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the input field for a tool call
|
||||
*/
|
||||
function formatToolInput(request: unknown): string {
|
||||
const requestFormatted = formatJsonValue(request);
|
||||
if (requestFormatted === "{}") {
|
||||
return "";
|
||||
}
|
||||
return formatIndentedField("input", requestFormatted);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the result field for a tool call, parsing JSON if possible
|
||||
*/
|
||||
function formatToolResult(result: string): string {
|
||||
try {
|
||||
const parsed = JSON.parse(result);
|
||||
const formatted = formatJsonValue(parsed);
|
||||
return formatIndentedField("result", formatted);
|
||||
} catch {
|
||||
// Not JSON, display as-is
|
||||
return formatIndentedField("result", result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a complete tool call entry with tool name, input, result, and error
|
||||
*/
|
||||
function formatToolCall({
|
||||
toolName,
|
||||
request,
|
||||
result,
|
||||
error,
|
||||
}: {
|
||||
toolName: string;
|
||||
request: unknown;
|
||||
result?: string;
|
||||
error?: string;
|
||||
}): string {
|
||||
let logEntry = `→ ${toolName}\n`;
|
||||
|
||||
logEntry += formatToolInput(request);
|
||||
|
||||
if (error) {
|
||||
logEntry += formatIndentedField("error", error);
|
||||
} else if (result) {
|
||||
logEntry += formatToolResult(result);
|
||||
}
|
||||
|
||||
logEntry += "\n";
|
||||
return logEntry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a CLI executable path by checking if it's installed globally
|
||||
* @param name The name of the CLI executable to find
|
||||
|
||||
+20
-4
@@ -241,21 +241,37 @@ async function acquireNewToken(): Promise<string> {
|
||||
}
|
||||
}
|
||||
|
||||
// Store token in memory instead of process.env
|
||||
let githubInstallationToken: string | undefined;
|
||||
|
||||
/**
|
||||
* Setup GitHub installation token for the action
|
||||
*/
|
||||
export async function setupGitHubInstallationToken(): Promise<string> {
|
||||
const acquiredToken = await acquireNewToken();
|
||||
core.setSecret(acquiredToken);
|
||||
process.env.GITHUB_INSTALLATION_TOKEN = acquiredToken;
|
||||
|
||||
githubInstallationToken = acquiredToken;
|
||||
return acquiredToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* Revoke GitHub installation token
|
||||
* Get the GitHub installation token from memory
|
||||
*/
|
||||
export async function revokeInstallationToken(token: string): Promise<void> {
|
||||
export function getGitHubInstallationToken(): string {
|
||||
if (!githubInstallationToken) {
|
||||
throw new Error("GitHub installation token not set. Call setupGitHubInstallationToken first.");
|
||||
}
|
||||
return githubInstallationToken;
|
||||
}
|
||||
|
||||
export async function revokeGitHubInstallationToken(): Promise<void> {
|
||||
if (!githubInstallationToken) {
|
||||
return;
|
||||
}
|
||||
|
||||
const token = githubInstallationToken;
|
||||
githubInstallationToken = undefined;
|
||||
|
||||
const apiUrl = process.env.GITHUB_API_URL || "https://api.github.com";
|
||||
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user