e409c57d90
* feat: add mcp_config input that merges with existing mcp server - Add mcp_config input parameter to action.yml - Modify prepareMcpConfig() to accept and merge additional config - Provided config overrides built-in servers in case of naming collisions - Pass MCP_CONFIG environment variable from action to prepare step Co-authored-by: ashwin-ant <ashwin-ant@users.noreply.github.com> * refactor: improve MCP config validation and merging logic - Add JSON validation to ensure parsed config is an object - Simplify merge logic with explicit mcpServers merging - Enhance error logging with config preview for debugging Co-authored-by: ashwin-ant <ashwin-ant@users.noreply.github.com> * refactor: improve MCP config logging per review feedback - Remove configPreview from error logging to avoid cluttering output - Add informational log when merging MCP server configurations - Simplify error message for failed config parsing Co-authored-by: ashwin-ant <ashwin-ant@users.noreply.github.com> * test: add comprehensive unit tests for prepareMcpConfig Add tests covering: - Basic functionality with no additional config - Valid JSON merging scenarios - Invalid JSON handling - Empty/null config handling - Server name collision scenarios - Complex nested configurations - Environment variable handling Co-authored-by: ashwin-ant <ashwin-ant@users.noreply.github.com> * docs: add mcp_config example with sequential-thinking server - Add mcp_config to inputs table - Add example section showing how to use mcp_config with sequential-thinking MCP server - Include clear explanation that custom servers override built-in servers Co-authored-by: ashwin-ant <ashwin-ant@users.noreply.github.com> * readme --------- Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com> Co-authored-by: ashwin-ant <ashwin-ant@users.noreply.github.com>
108 lines
3.4 KiB
TypeScript
108 lines
3.4 KiB
TypeScript
#!/usr/bin/env bun
|
|
|
|
/**
|
|
* Prepare the Claude action by checking trigger conditions, verifying human actor,
|
|
* and creating the initial tracking comment
|
|
*/
|
|
|
|
import * as core from "@actions/core";
|
|
import { setupGitHubToken } from "../github/token";
|
|
import { checkTriggerAction } from "../github/validation/trigger";
|
|
import { checkHumanActor } from "../github/validation/actor";
|
|
import { checkWritePermissions } from "../github/validation/permissions";
|
|
import { createInitialComment } from "../github/operations/comments/create-initial";
|
|
import { setupBranch } from "../github/operations/branch";
|
|
import { updateTrackingComment } from "../github/operations/comments/update-with-branch";
|
|
import { prepareMcpConfig } from "../mcp/install-mcp-server";
|
|
import { createPrompt } from "../create-prompt";
|
|
import { createOctokit } from "../github/api/client";
|
|
import { fetchGitHubData } from "../github/data/fetcher";
|
|
import { parseGitHubContext } from "../github/context";
|
|
|
|
async function run() {
|
|
try {
|
|
// Step 1: Setup GitHub token
|
|
const githubToken = await setupGitHubToken();
|
|
const octokit = createOctokit(githubToken);
|
|
|
|
// Step 2: Parse GitHub context (once for all operations)
|
|
const context = parseGitHubContext();
|
|
|
|
// Step 3: Check write permissions
|
|
const hasWritePermissions = await checkWritePermissions(
|
|
octokit.rest,
|
|
context,
|
|
);
|
|
if (!hasWritePermissions) {
|
|
throw new Error(
|
|
"Actor does not have write permissions to the repository",
|
|
);
|
|
}
|
|
|
|
// Step 4: Check trigger conditions
|
|
const containsTrigger = await checkTriggerAction(context);
|
|
|
|
if (!containsTrigger) {
|
|
console.log("No trigger found, skipping remaining steps");
|
|
return;
|
|
}
|
|
|
|
// Step 5: Check if actor is human
|
|
await checkHumanActor(octokit.rest, context);
|
|
|
|
// Step 6: Create initial tracking comment
|
|
const commentId = await createInitialComment(octokit.rest, context);
|
|
|
|
// Step 7: Fetch GitHub data (once for both branch setup and prompt creation)
|
|
const githubData = await fetchGitHubData({
|
|
octokits: octokit,
|
|
repository: `${context.repository.owner}/${context.repository.repo}`,
|
|
prNumber: context.entityNumber.toString(),
|
|
isPR: context.isPR,
|
|
});
|
|
|
|
// Step 8: Setup branch
|
|
const branchInfo = await setupBranch(octokit, githubData, context);
|
|
|
|
// Step 9: Update initial comment with branch link (only for issues that created a new branch)
|
|
if (branchInfo.claudeBranch) {
|
|
await updateTrackingComment(
|
|
octokit,
|
|
context,
|
|
commentId,
|
|
branchInfo.claudeBranch,
|
|
);
|
|
}
|
|
|
|
// Step 10: Create prompt file
|
|
await createPrompt(
|
|
commentId,
|
|
branchInfo.baseBranch,
|
|
branchInfo.claudeBranch,
|
|
githubData,
|
|
context,
|
|
);
|
|
|
|
// Step 11: Get MCP configuration
|
|
const additionalMcpConfig = process.env.MCP_CONFIG || "";
|
|
const mcpConfig = await prepareMcpConfig(
|
|
githubToken,
|
|
context.repository.owner,
|
|
context.repository.repo,
|
|
branchInfo.currentBranch,
|
|
additionalMcpConfig,
|
|
);
|
|
core.setOutput("mcp_config", mcpConfig);
|
|
} catch (error) {
|
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
core.setFailed(`Prepare step failed with error: ${errorMessage}`);
|
|
// Also output the clean error message for the action to capture
|
|
core.setOutput("prepare_error", errorMessage);
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
if (import.meta.main) {
|
|
run();
|
|
}
|