mirror of
https://github.com/anthropics/claude-code-action.git
synced 2026-01-23 15:04:13 +08:00
Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
37483ba112 | ||
|
|
9b50f473cb | ||
|
|
47ea5c2a69 | ||
|
|
4bd9c2053a | ||
|
|
f862b5a16a | ||
|
|
424d1b8f87 | ||
|
|
1d5e695d0c | ||
|
|
8e8be41f15 | ||
|
|
c7957fda5d | ||
|
|
1990b0bdb3 | ||
|
|
699aa26b41 | ||
|
|
94c0c31c1b | ||
|
|
be799cbe7b | ||
|
|
bd71ac0e8f |
2
.github/workflows/claude-review.yml
vendored
2
.github/workflows/claude-review.yml
vendored
@@ -29,4 +29,4 @@ jobs:
|
|||||||
|
|
||||||
Be constructive and specific in your feedback. Give inline comments where applicable.
|
Be constructive and specific in your feedback. Give inline comments where applicable.
|
||||||
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
|
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
|
||||||
allowed_tools: "mcp__github__add_pull_request_review_comment"
|
allowed_tools: "mcp__github__create_pending_pull_request_review,mcp__github__add_pull_request_review_comment_to_pending_review,mcp__github__submit_pending_pull_request_review,mcp__github__get_pull_request_diff"
|
||||||
|
|||||||
26
.github/workflows/issue-triage.yml
vendored
26
.github/workflows/issue-triage.yml
vendored
@@ -23,18 +23,20 @@ jobs:
|
|||||||
mkdir -p /tmp/mcp-config
|
mkdir -p /tmp/mcp-config
|
||||||
cat > /tmp/mcp-config/mcp-servers.json << 'EOF'
|
cat > /tmp/mcp-config/mcp-servers.json << 'EOF'
|
||||||
{
|
{
|
||||||
"github": {
|
"mcpServers": {
|
||||||
"command": "docker",
|
"github": {
|
||||||
"args": [
|
"command": "docker",
|
||||||
"run",
|
"args": [
|
||||||
"-i",
|
"run",
|
||||||
"--rm",
|
"-i",
|
||||||
"-e",
|
"--rm",
|
||||||
"GITHUB_PERSONAL_ACCESS_TOKEN",
|
"-e",
|
||||||
"ghcr.io/github/github-mcp-server:sha-7aced2b"
|
"GITHUB_PERSONAL_ACCESS_TOKEN",
|
||||||
],
|
"ghcr.io/github/github-mcp-server:sha-7aced2b"
|
||||||
"env": {
|
],
|
||||||
"GITHUB_PERSONAL_ACCESS_TOKEN": "${{ secrets.GITHUB_TOKEN }}"
|
"env": {
|
||||||
|
"GITHUB_PERSONAL_ACCESS_TOKEN": "${{ secrets.GITHUB_TOKEN }}"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
21
README.md
21
README.md
@@ -70,6 +70,8 @@ jobs:
|
|||||||
# NODE_ENV: test
|
# NODE_ENV: test
|
||||||
# DEBUG: true
|
# DEBUG: true
|
||||||
# API_URL: https://api.example.com
|
# API_URL: https://api.example.com
|
||||||
|
# Optional: limit the number of conversation turns
|
||||||
|
# max_turns: "5"
|
||||||
```
|
```
|
||||||
|
|
||||||
## Inputs
|
## Inputs
|
||||||
@@ -78,6 +80,7 @@ jobs:
|
|||||||
| --------------------- | -------------------------------------------------------------------------------------------------------------------- | -------- | --------- |
|
| --------------------- | -------------------------------------------------------------------------------------------------------------------- | -------- | --------- |
|
||||||
| `anthropic_api_key` | Anthropic API key (required for direct API, not needed for Bedrock/Vertex) | No\* | - |
|
| `anthropic_api_key` | Anthropic API key (required for direct API, not needed for Bedrock/Vertex) | No\* | - |
|
||||||
| `direct_prompt` | Direct prompt for Claude to execute automatically without needing a trigger (for automated workflows) | No | - |
|
| `direct_prompt` | Direct prompt for Claude to execute automatically without needing a trigger (for automated workflows) | No | - |
|
||||||
|
| `max_turns` | Maximum number of conversation turns Claude can take (limits back-and-forth exchanges) | No | - |
|
||||||
| `timeout_minutes` | Timeout in minutes for execution | No | `30` |
|
| `timeout_minutes` | Timeout in minutes for execution | No | `30` |
|
||||||
| `github_token` | GitHub token for Claude to operate with. **Only include this if you're connecting a custom GitHub app of your own!** | No | - |
|
| `github_token` | GitHub token for Claude to operate with. **Only include this if you're connecting a custom GitHub app of your own!** | No | - |
|
||||||
| `model` | Model to use (provider-specific format required for Bedrock/Vertex) | No | - |
|
| `model` | Model to use (provider-specific format required for Bedrock/Vertex) | No | - |
|
||||||
@@ -311,6 +314,24 @@ You can pass custom environment variables to Claude Code execution using the `cl
|
|||||||
|
|
||||||
The `claude_env` input accepts YAML format where each line defines a key-value pair. These environment variables will be available to Claude Code during execution, allowing it to run tests, build processes, or other commands that depend on specific environment configurations.
|
The `claude_env` input accepts YAML format where each line defines a key-value pair. These environment variables will be available to Claude Code during execution, allowing it to run tests, build processes, or other commands that depend on specific environment configurations.
|
||||||
|
|
||||||
|
### Limiting Conversation Turns
|
||||||
|
|
||||||
|
You can use the `max_turns` parameter to limit the number of back-and-forth exchanges Claude can have during task execution. This is useful for:
|
||||||
|
|
||||||
|
- Controlling costs by preventing runaway conversations
|
||||||
|
- Setting time boundaries for automated workflows
|
||||||
|
- Ensuring predictable behavior in CI/CD pipelines
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- uses: anthropics/claude-code-action@beta
|
||||||
|
with:
|
||||||
|
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
|
||||||
|
max_turns: "5" # Limit to 5 conversation turns
|
||||||
|
# ... other inputs
|
||||||
|
```
|
||||||
|
|
||||||
|
When the turn limit is reached, Claude will stop execution gracefully. Choose a value that gives Claude enough turns to complete typical tasks while preventing excessive usage.
|
||||||
|
|
||||||
### Custom Tools
|
### Custom Tools
|
||||||
|
|
||||||
By default, Claude only has access to:
|
By default, Claude only has access to:
|
||||||
|
|||||||
15
action.yml
15
action.yml
@@ -62,6 +62,10 @@ inputs:
|
|||||||
required: false
|
required: false
|
||||||
default: "false"
|
default: "false"
|
||||||
|
|
||||||
|
max_turns:
|
||||||
|
description: "Maximum number of conversation turns"
|
||||||
|
required: false
|
||||||
|
default: ""
|
||||||
timeout_minutes:
|
timeout_minutes:
|
||||||
description: "Timeout in minutes for execution"
|
description: "Timeout in minutes for execution"
|
||||||
required: false
|
required: false
|
||||||
@@ -83,14 +87,14 @@ runs:
|
|||||||
- name: Install Dependencies
|
- name: Install Dependencies
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
cd ${{ github.action_path }}
|
cd ${GITHUB_ACTION_PATH}
|
||||||
bun install
|
bun install
|
||||||
|
|
||||||
- name: Prepare action
|
- name: Prepare action
|
||||||
id: prepare
|
id: prepare
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
bun run ${{ github.action_path }}/src/entrypoints/prepare.ts
|
bun run ${GITHUB_ACTION_PATH}/src/entrypoints/prepare.ts
|
||||||
env:
|
env:
|
||||||
TRIGGER_PHRASE: ${{ inputs.trigger_phrase }}
|
TRIGGER_PHRASE: ${{ inputs.trigger_phrase }}
|
||||||
ASSIGNEE_TRIGGER: ${{ inputs.assignee_trigger }}
|
ASSIGNEE_TRIGGER: ${{ inputs.assignee_trigger }}
|
||||||
@@ -105,12 +109,13 @@ runs:
|
|||||||
- name: Run Claude Code
|
- name: Run Claude Code
|
||||||
id: claude-code
|
id: claude-code
|
||||||
if: steps.prepare.outputs.contains_trigger == 'true'
|
if: steps.prepare.outputs.contains_trigger == 'true'
|
||||||
uses: anthropics/claude-code-base-action@1370ac97fbba9bddec20ea2924b5726bf10d8b94 # v0.0.9
|
uses: anthropics/claude-code-base-action@79b8cfc932eb13806c23905842145e6f05c89e2e # v0.0.13
|
||||||
with:
|
with:
|
||||||
prompt_file: /tmp/claude-prompts/claude-prompt.txt
|
prompt_file: ${{ runner.temp }}/claude-prompts/claude-prompt.txt
|
||||||
allowed_tools: ${{ env.ALLOWED_TOOLS }}
|
allowed_tools: ${{ env.ALLOWED_TOOLS }}
|
||||||
disallowed_tools: ${{ env.DISALLOWED_TOOLS }}
|
disallowed_tools: ${{ env.DISALLOWED_TOOLS }}
|
||||||
timeout_minutes: ${{ inputs.timeout_minutes }}
|
timeout_minutes: ${{ inputs.timeout_minutes }}
|
||||||
|
max_turns: ${{ inputs.max_turns }}
|
||||||
model: ${{ inputs.model || inputs.anthropic_model }}
|
model: ${{ inputs.model || inputs.anthropic_model }}
|
||||||
mcp_config: ${{ steps.prepare.outputs.mcp_config }}
|
mcp_config: ${{ steps.prepare.outputs.mcp_config }}
|
||||||
use_bedrock: ${{ inputs.use_bedrock }}
|
use_bedrock: ${{ inputs.use_bedrock }}
|
||||||
@@ -147,7 +152,7 @@ runs:
|
|||||||
if: steps.prepare.outputs.contains_trigger == 'true' && steps.prepare.outputs.claude_comment_id && always()
|
if: steps.prepare.outputs.contains_trigger == 'true' && steps.prepare.outputs.claude_comment_id && always()
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
bun run ${{ github.action_path }}/src/entrypoints/update-comment-link.ts
|
bun run ${GITHUB_ACTION_PATH}/src/entrypoints/update-comment-link.ts
|
||||||
env:
|
env:
|
||||||
REPOSITORY: ${{ github.repository }}
|
REPOSITORY: ${{ github.repository }}
|
||||||
PR_NUMBER: ${{ github.event.issue.number || github.event.pull_request.number }}
|
PR_NUMBER: ${{ github.event.issue.number || github.event.pull_request.number }}
|
||||||
|
|||||||
2
bun.lock
2
bun.lock
@@ -2,7 +2,7 @@
|
|||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"workspaces": {
|
"workspaces": {
|
||||||
"": {
|
"": {
|
||||||
"name": "claude-pr-action",
|
"name": "@anthropic-ai/claude-code-action",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/core": "^1.10.1",
|
"@actions/core": "^1.10.1",
|
||||||
"@actions/github": "^6.0.1",
|
"@actions/github": "^6.0.1",
|
||||||
|
|||||||
@@ -35,4 +35,4 @@ jobs:
|
|||||||
|
|
||||||
Provide constructive feedback with specific suggestions for improvement.
|
Provide constructive feedback with specific suggestions for improvement.
|
||||||
Use inline comments to highlight specific areas of concern.
|
Use inline comments to highlight specific areas of concern.
|
||||||
# allowed_tools: "mcp__github__add_pull_request_review_comment"
|
# allowed_tools: "mcp__github__create_pending_pull_request_review,mcp__github__add_pull_request_review_comment_to_pending_review,mcp__github__submit_pending_pull_request_review,mcp__github__get_pull_request_diff"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "claude-pr-action",
|
"name": "@anthropic-ai/claude-code-action",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -35,38 +35,35 @@ const BASE_ALLOWED_TOOLS = [
|
|||||||
];
|
];
|
||||||
const DISALLOWED_TOOLS = ["WebSearch", "WebFetch"];
|
const DISALLOWED_TOOLS = ["WebSearch", "WebFetch"];
|
||||||
|
|
||||||
export function buildAllowedToolsString(customAllowedTools?: string): string {
|
export function buildAllowedToolsString(customAllowedTools?: string[]): string {
|
||||||
let baseTools = [...BASE_ALLOWED_TOOLS];
|
let baseTools = [...BASE_ALLOWED_TOOLS];
|
||||||
|
|
||||||
let allAllowedTools = baseTools.join(",");
|
let allAllowedTools = baseTools.join(",");
|
||||||
if (customAllowedTools) {
|
if (customAllowedTools && customAllowedTools.length > 0) {
|
||||||
allAllowedTools = `${allAllowedTools},${customAllowedTools}`;
|
allAllowedTools = `${allAllowedTools},${customAllowedTools.join(",")}`;
|
||||||
}
|
}
|
||||||
return allAllowedTools;
|
return allAllowedTools;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function buildDisallowedToolsString(
|
export function buildDisallowedToolsString(
|
||||||
customDisallowedTools?: string,
|
customDisallowedTools?: string[],
|
||||||
allowedTools?: string,
|
allowedTools?: string[],
|
||||||
): string {
|
): string {
|
||||||
let disallowedTools = [...DISALLOWED_TOOLS];
|
let disallowedTools = [...DISALLOWED_TOOLS];
|
||||||
|
|
||||||
// If user has explicitly allowed some hardcoded disallowed tools, remove them from disallowed list
|
// If user has explicitly allowed some hardcoded disallowed tools, remove them from disallowed list
|
||||||
if (allowedTools) {
|
if (allowedTools && allowedTools.length > 0) {
|
||||||
const allowedToolsArray = allowedTools
|
|
||||||
.split(",")
|
|
||||||
.map((tool) => tool.trim());
|
|
||||||
disallowedTools = disallowedTools.filter(
|
disallowedTools = disallowedTools.filter(
|
||||||
(tool) => !allowedToolsArray.includes(tool),
|
(tool) => !allowedTools.includes(tool),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let allDisallowedTools = disallowedTools.join(",");
|
let allDisallowedTools = disallowedTools.join(",");
|
||||||
if (customDisallowedTools) {
|
if (customDisallowedTools && customDisallowedTools.length > 0) {
|
||||||
if (allDisallowedTools) {
|
if (allDisallowedTools) {
|
||||||
allDisallowedTools = `${allDisallowedTools},${customDisallowedTools}`;
|
allDisallowedTools = `${allDisallowedTools},${customDisallowedTools.join(",")}`;
|
||||||
} else {
|
} else {
|
||||||
allDisallowedTools = customDisallowedTools;
|
allDisallowedTools = customDisallowedTools.join(",");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return allDisallowedTools;
|
return allDisallowedTools;
|
||||||
@@ -120,8 +117,10 @@ export function prepareContext(
|
|||||||
triggerPhrase,
|
triggerPhrase,
|
||||||
...(triggerUsername && { triggerUsername }),
|
...(triggerUsername && { triggerUsername }),
|
||||||
...(customInstructions && { customInstructions }),
|
...(customInstructions && { customInstructions }),
|
||||||
...(allowedTools && { allowedTools }),
|
...(allowedTools.length > 0 && { allowedTools: allowedTools.join(",") }),
|
||||||
...(disallowedTools && { disallowedTools }),
|
...(disallowedTools.length > 0 && {
|
||||||
|
disallowedTools: disallowedTools.join(","),
|
||||||
|
}),
|
||||||
...(directPrompt && { directPrompt }),
|
...(directPrompt && { directPrompt }),
|
||||||
...(claudeBranch && { claudeBranch }),
|
...(claudeBranch && { claudeBranch }),
|
||||||
};
|
};
|
||||||
@@ -621,7 +620,9 @@ export async function createPrompt(
|
|||||||
claudeBranch,
|
claudeBranch,
|
||||||
);
|
);
|
||||||
|
|
||||||
await mkdir("/tmp/claude-prompts", { recursive: true });
|
await mkdir(`${process.env.RUNNER_TEMP}/claude-prompts`, {
|
||||||
|
recursive: true,
|
||||||
|
});
|
||||||
|
|
||||||
// Generate the prompt
|
// Generate the prompt
|
||||||
const promptContent = generatePrompt(preparedContext, githubData);
|
const promptContent = generatePrompt(preparedContext, githubData);
|
||||||
@@ -632,15 +633,18 @@ export async function createPrompt(
|
|||||||
console.log("=======================");
|
console.log("=======================");
|
||||||
|
|
||||||
// Write the prompt file
|
// Write the prompt file
|
||||||
await writeFile("/tmp/claude-prompts/claude-prompt.txt", promptContent);
|
await writeFile(
|
||||||
|
`${process.env.RUNNER_TEMP}/claude-prompts/claude-prompt.txt`,
|
||||||
|
promptContent,
|
||||||
|
);
|
||||||
|
|
||||||
// Set allowed tools
|
// Set allowed tools
|
||||||
const allAllowedTools = buildAllowedToolsString(
|
const allAllowedTools = buildAllowedToolsString(
|
||||||
preparedContext.allowedTools,
|
context.inputs.allowedTools,
|
||||||
);
|
);
|
||||||
const allDisallowedTools = buildDisallowedToolsString(
|
const allDisallowedTools = buildDisallowedToolsString(
|
||||||
preparedContext.disallowedTools,
|
context.inputs.disallowedTools,
|
||||||
preparedContext.allowedTools,
|
context.inputs.allowedTools,
|
||||||
);
|
);
|
||||||
|
|
||||||
core.exportVariable("ALLOWED_TOOLS", allAllowedTools);
|
core.exportVariable("ALLOWED_TOOLS", allAllowedTools);
|
||||||
|
|||||||
@@ -92,6 +92,7 @@ async function run() {
|
|||||||
branch: branchInfo.currentBranch,
|
branch: branchInfo.currentBranch,
|
||||||
additionalMcpConfig,
|
additionalMcpConfig,
|
||||||
claudeCommentId: commentId.toString(),
|
claudeCommentId: commentId.toString(),
|
||||||
|
allowedTools: context.inputs.allowedTools,
|
||||||
});
|
});
|
||||||
core.setOutput("mcp_config", mcpConfig);
|
core.setOutput("mcp_config", mcpConfig);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -28,8 +28,8 @@ export type ParsedGitHubContext = {
|
|||||||
inputs: {
|
inputs: {
|
||||||
triggerPhrase: string;
|
triggerPhrase: string;
|
||||||
assigneeTrigger: string;
|
assigneeTrigger: string;
|
||||||
allowedTools: string;
|
allowedTools: string[];
|
||||||
disallowedTools: string;
|
disallowedTools: string[];
|
||||||
customInstructions: string;
|
customInstructions: string;
|
||||||
directPrompt: string;
|
directPrompt: string;
|
||||||
baseBranch?: string;
|
baseBranch?: string;
|
||||||
@@ -52,8 +52,14 @@ export function parseGitHubContext(): ParsedGitHubContext {
|
|||||||
inputs: {
|
inputs: {
|
||||||
triggerPhrase: process.env.TRIGGER_PHRASE ?? "@claude",
|
triggerPhrase: process.env.TRIGGER_PHRASE ?? "@claude",
|
||||||
assigneeTrigger: process.env.ASSIGNEE_TRIGGER ?? "",
|
assigneeTrigger: process.env.ASSIGNEE_TRIGGER ?? "",
|
||||||
allowedTools: process.env.ALLOWED_TOOLS ?? "",
|
allowedTools: (process.env.ALLOWED_TOOLS ?? "")
|
||||||
disallowedTools: process.env.DISALLOWED_TOOLS ?? "",
|
.split(",")
|
||||||
|
.map((tool) => tool.trim())
|
||||||
|
.filter((tool) => tool.length > 0),
|
||||||
|
disallowedTools: (process.env.DISALLOWED_TOOLS ?? "")
|
||||||
|
.split(",")
|
||||||
|
.map((tool) => tool.trim())
|
||||||
|
.filter((tool) => tool.length > 0),
|
||||||
customInstructions: process.env.CUSTOM_INSTRUCTIONS ?? "",
|
customInstructions: process.env.CUSTOM_INSTRUCTIONS ?? "",
|
||||||
directPrompt: process.env.DIRECT_PROMPT ?? "",
|
directPrompt: process.env.DIRECT_PROMPT ?? "",
|
||||||
baseBranch: process.env.BASE_BRANCH,
|
baseBranch: process.env.BASE_BRANCH,
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
import { execSync } from "child_process";
|
import { execSync } from "child_process";
|
||||||
|
import type { Octokits } from "../api/client";
|
||||||
|
import { ISSUE_QUERY, PR_QUERY } from "../api/queries/github";
|
||||||
import type {
|
import type {
|
||||||
GitHubPullRequest,
|
|
||||||
GitHubIssue,
|
|
||||||
GitHubComment,
|
GitHubComment,
|
||||||
GitHubFile,
|
GitHubFile,
|
||||||
|
GitHubIssue,
|
||||||
|
GitHubPullRequest,
|
||||||
GitHubReview,
|
GitHubReview,
|
||||||
PullRequestQueryResponse,
|
|
||||||
IssueQueryResponse,
|
IssueQueryResponse,
|
||||||
|
PullRequestQueryResponse,
|
||||||
} from "../types";
|
} from "../types";
|
||||||
import { PR_QUERY, ISSUE_QUERY } from "../api/queries/github";
|
|
||||||
import type { Octokits } from "../api/client";
|
|
||||||
import { downloadCommentImages } from "../utils/image-downloader";
|
|
||||||
import type { CommentWithImages } from "../utils/image-downloader";
|
import type { CommentWithImages } from "../utils/image-downloader";
|
||||||
|
import { downloadCommentImages } from "../utils/image-downloader";
|
||||||
|
|
||||||
type FetchDataParams = {
|
type FetchDataParams = {
|
||||||
octokits: Octokits;
|
octokits: Octokits;
|
||||||
@@ -101,6 +101,14 @@ export async function fetchGitHubData({
|
|||||||
let changedFilesWithSHA: GitHubFileWithSHA[] = [];
|
let changedFilesWithSHA: GitHubFileWithSHA[] = [];
|
||||||
if (isPR && changedFiles.length > 0) {
|
if (isPR && changedFiles.length > 0) {
|
||||||
changedFilesWithSHA = changedFiles.map((file) => {
|
changedFilesWithSHA = changedFiles.map((file) => {
|
||||||
|
// Don't compute SHA for deleted files
|
||||||
|
if (file.changeType === "DELETED") {
|
||||||
|
return {
|
||||||
|
...file,
|
||||||
|
sha: "deleted",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Use git hash-object to compute the SHA for the current file content
|
// Use git hash-object to compute the SHA for the current file content
|
||||||
const sha = execSync(`git hash-object "${file.path}"`, {
|
const sha = execSync(`git hash-object "${file.path}"`, {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ type PrepareConfigParams = {
|
|||||||
branch: string;
|
branch: string;
|
||||||
additionalMcpConfig?: string;
|
additionalMcpConfig?: string;
|
||||||
claudeCommentId?: string;
|
claudeCommentId?: string;
|
||||||
|
allowedTools: string[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export async function prepareMcpConfig(
|
export async function prepareMcpConfig(
|
||||||
@@ -19,24 +20,17 @@ export async function prepareMcpConfig(
|
|||||||
branch,
|
branch,
|
||||||
additionalMcpConfig,
|
additionalMcpConfig,
|
||||||
claudeCommentId,
|
claudeCommentId,
|
||||||
|
allowedTools,
|
||||||
} = params;
|
} = params;
|
||||||
try {
|
try {
|
||||||
const baseMcpConfig = {
|
const allowedToolsList = allowedTools || [];
|
||||||
|
|
||||||
|
const hasGitHubMcpTools = allowedToolsList.some((tool) =>
|
||||||
|
tool.startsWith("mcp__github__"),
|
||||||
|
);
|
||||||
|
|
||||||
|
const baseMcpConfig: { mcpServers: Record<string, unknown> } = {
|
||||||
mcpServers: {
|
mcpServers: {
|
||||||
github: {
|
|
||||||
command: "docker",
|
|
||||||
args: [
|
|
||||||
"run",
|
|
||||||
"-i",
|
|
||||||
"--rm",
|
|
||||||
"-e",
|
|
||||||
"GITHUB_PERSONAL_ACCESS_TOKEN",
|
|
||||||
"ghcr.io/anthropics/github-mcp-server:sha-7382253",
|
|
||||||
],
|
|
||||||
env: {
|
|
||||||
GITHUB_PERSONAL_ACCESS_TOKEN: githubToken,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
github_file_ops: {
|
github_file_ops: {
|
||||||
command: "bun",
|
command: "bun",
|
||||||
args: [
|
args: [
|
||||||
@@ -57,6 +51,23 @@ export async function prepareMcpConfig(
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (hasGitHubMcpTools) {
|
||||||
|
baseMcpConfig.mcpServers.github = {
|
||||||
|
command: "docker",
|
||||||
|
args: [
|
||||||
|
"run",
|
||||||
|
"-i",
|
||||||
|
"--rm",
|
||||||
|
"-e",
|
||||||
|
"GITHUB_PERSONAL_ACCESS_TOKEN",
|
||||||
|
"ghcr.io/github/github-mcp-server:sha-e9f748f", // https://github.com/github/github-mcp-server/releases/tag/v0.4.0
|
||||||
|
],
|
||||||
|
env: {
|
||||||
|
GITHUB_PERSONAL_ACCESS_TOKEN: githubToken,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// Merge with additional MCP config if provided
|
// Merge with additional MCP config if provided
|
||||||
if (additionalMcpConfig && additionalMcpConfig.trim()) {
|
if (additionalMcpConfig && additionalMcpConfig.trim()) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -652,7 +652,7 @@ describe("buildAllowedToolsString", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test("should append custom tools when provided", () => {
|
test("should append custom tools when provided", () => {
|
||||||
const customTools = "Tool1,Tool2,Tool3";
|
const customTools = ["Tool1", "Tool2", "Tool3"];
|
||||||
const result = buildAllowedToolsString(customTools);
|
const result = buildAllowedToolsString(customTools);
|
||||||
|
|
||||||
// Base tools should be present
|
// Base tools should be present
|
||||||
@@ -683,7 +683,7 @@ describe("buildDisallowedToolsString", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test("should append custom disallowed tools when provided", () => {
|
test("should append custom disallowed tools when provided", () => {
|
||||||
const customDisallowedTools = "BadTool1,BadTool2";
|
const customDisallowedTools = ["BadTool1", "BadTool2"];
|
||||||
const result = buildDisallowedToolsString(customDisallowedTools);
|
const result = buildDisallowedToolsString(customDisallowedTools);
|
||||||
|
|
||||||
// Base disallowed tools should be present
|
// Base disallowed tools should be present
|
||||||
@@ -701,8 +701,8 @@ describe("buildDisallowedToolsString", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test("should remove hardcoded disallowed tools if they are in allowed tools", () => {
|
test("should remove hardcoded disallowed tools if they are in allowed tools", () => {
|
||||||
const customDisallowedTools = "BadTool1,BadTool2";
|
const customDisallowedTools = ["BadTool1", "BadTool2"];
|
||||||
const allowedTools = "WebSearch,SomeOtherTool";
|
const allowedTools = ["WebSearch", "SomeOtherTool"];
|
||||||
const result = buildDisallowedToolsString(
|
const result = buildDisallowedToolsString(
|
||||||
customDisallowedTools,
|
customDisallowedTools,
|
||||||
allowedTools,
|
allowedTools,
|
||||||
@@ -720,7 +720,7 @@ describe("buildDisallowedToolsString", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test("should remove all hardcoded disallowed tools if they are all in allowed tools", () => {
|
test("should remove all hardcoded disallowed tools if they are all in allowed tools", () => {
|
||||||
const allowedTools = "WebSearch,WebFetch,SomeOtherTool";
|
const allowedTools = ["WebSearch", "WebFetch", "SomeOtherTool"];
|
||||||
const result = buildDisallowedToolsString(undefined, allowedTools);
|
const result = buildDisallowedToolsString(undefined, allowedTools);
|
||||||
|
|
||||||
// Both hardcoded disallowed tools should be removed
|
// Both hardcoded disallowed tools should be removed
|
||||||
@@ -732,8 +732,8 @@ describe("buildDisallowedToolsString", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test("should handle custom disallowed tools when all hardcoded tools are overridden", () => {
|
test("should handle custom disallowed tools when all hardcoded tools are overridden", () => {
|
||||||
const customDisallowedTools = "BadTool1,BadTool2";
|
const customDisallowedTools = ["BadTool1", "BadTool2"];
|
||||||
const allowedTools = "WebSearch,WebFetch";
|
const allowedTools = ["WebSearch", "WebFetch"];
|
||||||
const result = buildDisallowedToolsString(
|
const result = buildDisallowedToolsString(
|
||||||
customDisallowedTools,
|
customDisallowedTools,
|
||||||
allowedTools,
|
allowedTools,
|
||||||
|
|||||||
@@ -24,21 +24,19 @@ describe("prepareMcpConfig", () => {
|
|||||||
processExitSpy.mockRestore();
|
processExitSpy.mockRestore();
|
||||||
});
|
});
|
||||||
|
|
||||||
test("should return base config when no additional config is provided", async () => {
|
test("should return base config when no additional config is provided and no allowed_tools", async () => {
|
||||||
const result = await prepareMcpConfig({
|
const result = await prepareMcpConfig({
|
||||||
githubToken: "test-token",
|
githubToken: "test-token",
|
||||||
owner: "test-owner",
|
owner: "test-owner",
|
||||||
repo: "test-repo",
|
repo: "test-repo",
|
||||||
branch: "test-branch",
|
branch: "test-branch",
|
||||||
|
allowedTools: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
const parsed = JSON.parse(result);
|
const parsed = JSON.parse(result);
|
||||||
expect(parsed.mcpServers).toBeDefined();
|
expect(parsed.mcpServers).toBeDefined();
|
||||||
expect(parsed.mcpServers.github).toBeDefined();
|
expect(parsed.mcpServers.github).not.toBeDefined();
|
||||||
expect(parsed.mcpServers.github_file_ops).toBeDefined();
|
expect(parsed.mcpServers.github_file_ops).toBeDefined();
|
||||||
expect(parsed.mcpServers.github.env.GITHUB_PERSONAL_ACCESS_TOKEN).toBe(
|
|
||||||
"test-token",
|
|
||||||
);
|
|
||||||
expect(parsed.mcpServers.github_file_ops.env.GITHUB_TOKEN).toBe(
|
expect(parsed.mcpServers.github_file_ops.env.GITHUB_TOKEN).toBe(
|
||||||
"test-token",
|
"test-token",
|
||||||
);
|
);
|
||||||
@@ -49,6 +47,60 @@ describe("prepareMcpConfig", () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("should include github MCP server when mcp__github__ tools are allowed", async () => {
|
||||||
|
const result = await prepareMcpConfig({
|
||||||
|
githubToken: "test-token",
|
||||||
|
owner: "test-owner",
|
||||||
|
repo: "test-repo",
|
||||||
|
branch: "test-branch",
|
||||||
|
allowedTools: [
|
||||||
|
"mcp__github__create_issue",
|
||||||
|
"mcp__github_file_ops__commit_files",
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
const parsed = JSON.parse(result);
|
||||||
|
expect(parsed.mcpServers).toBeDefined();
|
||||||
|
expect(parsed.mcpServers.github).toBeDefined();
|
||||||
|
expect(parsed.mcpServers.github_file_ops).toBeDefined();
|
||||||
|
expect(parsed.mcpServers.github.env.GITHUB_PERSONAL_ACCESS_TOKEN).toBe(
|
||||||
|
"test-token",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should not include github MCP server when only file_ops tools are allowed", async () => {
|
||||||
|
const result = await prepareMcpConfig({
|
||||||
|
githubToken: "test-token",
|
||||||
|
owner: "test-owner",
|
||||||
|
repo: "test-repo",
|
||||||
|
branch: "test-branch",
|
||||||
|
allowedTools: [
|
||||||
|
"mcp__github_file_ops__commit_files",
|
||||||
|
"mcp__github_file_ops__update_claude_comment",
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
const parsed = JSON.parse(result);
|
||||||
|
expect(parsed.mcpServers).toBeDefined();
|
||||||
|
expect(parsed.mcpServers.github).not.toBeDefined();
|
||||||
|
expect(parsed.mcpServers.github_file_ops).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should include file_ops server even when no GitHub tools are allowed", async () => {
|
||||||
|
const result = await prepareMcpConfig({
|
||||||
|
githubToken: "test-token",
|
||||||
|
owner: "test-owner",
|
||||||
|
repo: "test-repo",
|
||||||
|
branch: "test-branch",
|
||||||
|
allowedTools: ["Edit", "Read", "Write"],
|
||||||
|
});
|
||||||
|
|
||||||
|
const parsed = JSON.parse(result);
|
||||||
|
expect(parsed.mcpServers).toBeDefined();
|
||||||
|
expect(parsed.mcpServers.github).not.toBeDefined();
|
||||||
|
expect(parsed.mcpServers.github_file_ops).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
test("should return base config when additional config is empty string", async () => {
|
test("should return base config when additional config is empty string", async () => {
|
||||||
const result = await prepareMcpConfig({
|
const result = await prepareMcpConfig({
|
||||||
githubToken: "test-token",
|
githubToken: "test-token",
|
||||||
@@ -56,11 +108,12 @@ describe("prepareMcpConfig", () => {
|
|||||||
repo: "test-repo",
|
repo: "test-repo",
|
||||||
branch: "test-branch",
|
branch: "test-branch",
|
||||||
additionalMcpConfig: "",
|
additionalMcpConfig: "",
|
||||||
|
allowedTools: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
const parsed = JSON.parse(result);
|
const parsed = JSON.parse(result);
|
||||||
expect(parsed.mcpServers).toBeDefined();
|
expect(parsed.mcpServers).toBeDefined();
|
||||||
expect(parsed.mcpServers.github).toBeDefined();
|
expect(parsed.mcpServers.github).not.toBeDefined();
|
||||||
expect(parsed.mcpServers.github_file_ops).toBeDefined();
|
expect(parsed.mcpServers.github_file_ops).toBeDefined();
|
||||||
expect(consoleWarningSpy).not.toHaveBeenCalled();
|
expect(consoleWarningSpy).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
@@ -72,11 +125,12 @@ describe("prepareMcpConfig", () => {
|
|||||||
repo: "test-repo",
|
repo: "test-repo",
|
||||||
branch: "test-branch",
|
branch: "test-branch",
|
||||||
additionalMcpConfig: " \n\t ",
|
additionalMcpConfig: " \n\t ",
|
||||||
|
allowedTools: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
const parsed = JSON.parse(result);
|
const parsed = JSON.parse(result);
|
||||||
expect(parsed.mcpServers).toBeDefined();
|
expect(parsed.mcpServers).toBeDefined();
|
||||||
expect(parsed.mcpServers.github).toBeDefined();
|
expect(parsed.mcpServers.github).not.toBeDefined();
|
||||||
expect(parsed.mcpServers.github_file_ops).toBeDefined();
|
expect(parsed.mcpServers.github_file_ops).toBeDefined();
|
||||||
expect(consoleWarningSpy).not.toHaveBeenCalled();
|
expect(consoleWarningSpy).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
@@ -100,6 +154,10 @@ describe("prepareMcpConfig", () => {
|
|||||||
repo: "test-repo",
|
repo: "test-repo",
|
||||||
branch: "test-branch",
|
branch: "test-branch",
|
||||||
additionalMcpConfig: additionalConfig,
|
additionalMcpConfig: additionalConfig,
|
||||||
|
allowedTools: [
|
||||||
|
"mcp__github__create_issue",
|
||||||
|
"mcp__github_file_ops__commit_files",
|
||||||
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
const parsed = JSON.parse(result);
|
const parsed = JSON.parse(result);
|
||||||
@@ -133,6 +191,10 @@ describe("prepareMcpConfig", () => {
|
|||||||
repo: "test-repo",
|
repo: "test-repo",
|
||||||
branch: "test-branch",
|
branch: "test-branch",
|
||||||
additionalMcpConfig: additionalConfig,
|
additionalMcpConfig: additionalConfig,
|
||||||
|
allowedTools: [
|
||||||
|
"mcp__github__create_issue",
|
||||||
|
"mcp__github_file_ops__commit_files",
|
||||||
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
const parsed = JSON.parse(result);
|
const parsed = JSON.parse(result);
|
||||||
@@ -169,12 +231,13 @@ describe("prepareMcpConfig", () => {
|
|||||||
repo: "test-repo",
|
repo: "test-repo",
|
||||||
branch: "test-branch",
|
branch: "test-branch",
|
||||||
additionalMcpConfig: additionalConfig,
|
additionalMcpConfig: additionalConfig,
|
||||||
|
allowedTools: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
const parsed = JSON.parse(result);
|
const parsed = JSON.parse(result);
|
||||||
expect(parsed.customProperty).toBe("custom-value");
|
expect(parsed.customProperty).toBe("custom-value");
|
||||||
expect(parsed.anotherProperty).toEqual({ nested: "value" });
|
expect(parsed.anotherProperty).toEqual({ nested: "value" });
|
||||||
expect(parsed.mcpServers.github).toBeDefined();
|
expect(parsed.mcpServers.github).not.toBeDefined();
|
||||||
expect(parsed.mcpServers.custom_server).toBeDefined();
|
expect(parsed.mcpServers.custom_server).toBeDefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -187,13 +250,14 @@ describe("prepareMcpConfig", () => {
|
|||||||
repo: "test-repo",
|
repo: "test-repo",
|
||||||
branch: "test-branch",
|
branch: "test-branch",
|
||||||
additionalMcpConfig: invalidJson,
|
additionalMcpConfig: invalidJson,
|
||||||
|
allowedTools: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
const parsed = JSON.parse(result);
|
const parsed = JSON.parse(result);
|
||||||
expect(consoleWarningSpy).toHaveBeenCalledWith(
|
expect(consoleWarningSpy).toHaveBeenCalledWith(
|
||||||
expect.stringContaining("Failed to parse additional MCP config:"),
|
expect.stringContaining("Failed to parse additional MCP config:"),
|
||||||
);
|
);
|
||||||
expect(parsed.mcpServers.github).toBeDefined();
|
expect(parsed.mcpServers.github).not.toBeDefined();
|
||||||
expect(parsed.mcpServers.github_file_ops).toBeDefined();
|
expect(parsed.mcpServers.github_file_ops).toBeDefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -206,6 +270,7 @@ describe("prepareMcpConfig", () => {
|
|||||||
repo: "test-repo",
|
repo: "test-repo",
|
||||||
branch: "test-branch",
|
branch: "test-branch",
|
||||||
additionalMcpConfig: nonObjectJson,
|
additionalMcpConfig: nonObjectJson,
|
||||||
|
allowedTools: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
const parsed = JSON.parse(result);
|
const parsed = JSON.parse(result);
|
||||||
@@ -215,7 +280,7 @@ describe("prepareMcpConfig", () => {
|
|||||||
expect(consoleWarningSpy).toHaveBeenCalledWith(
|
expect(consoleWarningSpy).toHaveBeenCalledWith(
|
||||||
expect.stringContaining("MCP config must be a valid JSON object"),
|
expect.stringContaining("MCP config must be a valid JSON object"),
|
||||||
);
|
);
|
||||||
expect(parsed.mcpServers.github).toBeDefined();
|
expect(parsed.mcpServers.github).not.toBeDefined();
|
||||||
expect(parsed.mcpServers.github_file_ops).toBeDefined();
|
expect(parsed.mcpServers.github_file_ops).toBeDefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -228,6 +293,7 @@ describe("prepareMcpConfig", () => {
|
|||||||
repo: "test-repo",
|
repo: "test-repo",
|
||||||
branch: "test-branch",
|
branch: "test-branch",
|
||||||
additionalMcpConfig: nullJson,
|
additionalMcpConfig: nullJson,
|
||||||
|
allowedTools: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
const parsed = JSON.parse(result);
|
const parsed = JSON.parse(result);
|
||||||
@@ -237,7 +303,7 @@ describe("prepareMcpConfig", () => {
|
|||||||
expect(consoleWarningSpy).toHaveBeenCalledWith(
|
expect(consoleWarningSpy).toHaveBeenCalledWith(
|
||||||
expect.stringContaining("MCP config must be a valid JSON object"),
|
expect.stringContaining("MCP config must be a valid JSON object"),
|
||||||
);
|
);
|
||||||
expect(parsed.mcpServers.github).toBeDefined();
|
expect(parsed.mcpServers.github).not.toBeDefined();
|
||||||
expect(parsed.mcpServers.github_file_ops).toBeDefined();
|
expect(parsed.mcpServers.github_file_ops).toBeDefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -250,6 +316,7 @@ describe("prepareMcpConfig", () => {
|
|||||||
repo: "test-repo",
|
repo: "test-repo",
|
||||||
branch: "test-branch",
|
branch: "test-branch",
|
||||||
additionalMcpConfig: arrayJson,
|
additionalMcpConfig: arrayJson,
|
||||||
|
allowedTools: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
const parsed = JSON.parse(result);
|
const parsed = JSON.parse(result);
|
||||||
@@ -258,7 +325,7 @@ describe("prepareMcpConfig", () => {
|
|||||||
expect(consoleInfoSpy).toHaveBeenCalledWith(
|
expect(consoleInfoSpy).toHaveBeenCalledWith(
|
||||||
"Merging additional MCP server configuration with built-in servers",
|
"Merging additional MCP server configuration with built-in servers",
|
||||||
);
|
);
|
||||||
expect(parsed.mcpServers.github).toBeDefined();
|
expect(parsed.mcpServers.github).not.toBeDefined();
|
||||||
expect(parsed.mcpServers.github_file_ops).toBeDefined();
|
expect(parsed.mcpServers.github_file_ops).toBeDefined();
|
||||||
// The array will be spread into the config (0: 1, 1: 2, 2: 3)
|
// The array will be spread into the config (0: 1, 1: 2, 2: 3)
|
||||||
expect(parsed[0]).toBe(1);
|
expect(parsed[0]).toBe(1);
|
||||||
@@ -295,12 +362,13 @@ describe("prepareMcpConfig", () => {
|
|||||||
repo: "test-repo",
|
repo: "test-repo",
|
||||||
branch: "test-branch",
|
branch: "test-branch",
|
||||||
additionalMcpConfig: additionalConfig,
|
additionalMcpConfig: additionalConfig,
|
||||||
|
allowedTools: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
const parsed = JSON.parse(result);
|
const parsed = JSON.parse(result);
|
||||||
expect(parsed.mcpServers.server1).toBeDefined();
|
expect(parsed.mcpServers.server1).toBeDefined();
|
||||||
expect(parsed.mcpServers.server2).toBeDefined();
|
expect(parsed.mcpServers.server2).toBeDefined();
|
||||||
expect(parsed.mcpServers.github).toBeDefined();
|
expect(parsed.mcpServers.github).not.toBeDefined();
|
||||||
expect(parsed.mcpServers.github_file_ops.command).toBe("overridden");
|
expect(parsed.mcpServers.github_file_ops.command).toBe("overridden");
|
||||||
expect(parsed.mcpServers.github_file_ops.env.CUSTOM).toBe("value");
|
expect(parsed.mcpServers.github_file_ops.env.CUSTOM).toBe("value");
|
||||||
expect(parsed.otherConfig.nested.deeply).toBe("value");
|
expect(parsed.otherConfig.nested.deeply).toBe("value");
|
||||||
@@ -315,6 +383,7 @@ describe("prepareMcpConfig", () => {
|
|||||||
owner: "test-owner",
|
owner: "test-owner",
|
||||||
repo: "test-repo",
|
repo: "test-repo",
|
||||||
branch: "test-branch",
|
branch: "test-branch",
|
||||||
|
allowedTools: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
const parsed = JSON.parse(result);
|
const parsed = JSON.parse(result);
|
||||||
@@ -334,6 +403,7 @@ describe("prepareMcpConfig", () => {
|
|||||||
owner: "test-owner",
|
owner: "test-owner",
|
||||||
repo: "test-repo",
|
repo: "test-repo",
|
||||||
branch: "test-branch",
|
branch: "test-branch",
|
||||||
|
allowedTools: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
const parsed = JSON.parse(result);
|
const parsed = JSON.parse(result);
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ const defaultInputs = {
|
|||||||
triggerPhrase: "/claude",
|
triggerPhrase: "/claude",
|
||||||
assigneeTrigger: "",
|
assigneeTrigger: "",
|
||||||
anthropicModel: "claude-3-7-sonnet-20250219",
|
anthropicModel: "claude-3-7-sonnet-20250219",
|
||||||
allowedTools: "",
|
allowedTools: [] as string[],
|
||||||
disallowedTools: "",
|
disallowedTools: [] as string[],
|
||||||
customInstructions: "",
|
customInstructions: "",
|
||||||
directPrompt: "",
|
directPrompt: "",
|
||||||
useBedrock: false,
|
useBedrock: false,
|
||||||
|
|||||||
@@ -62,8 +62,8 @@ describe("checkWritePermissions", () => {
|
|||||||
inputs: {
|
inputs: {
|
||||||
triggerPhrase: "@claude",
|
triggerPhrase: "@claude",
|
||||||
assigneeTrigger: "",
|
assigneeTrigger: "",
|
||||||
allowedTools: "",
|
allowedTools: [],
|
||||||
disallowedTools: "",
|
disallowedTools: [],
|
||||||
customInstructions: "",
|
customInstructions: "",
|
||||||
directPrompt: "",
|
directPrompt: "",
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -242,7 +242,7 @@ describe("parseEnvVarsWithContext", () => {
|
|||||||
...mockPullRequestCommentContext,
|
...mockPullRequestCommentContext,
|
||||||
inputs: {
|
inputs: {
|
||||||
...mockPullRequestCommentContext.inputs,
|
...mockPullRequestCommentContext.inputs,
|
||||||
allowedTools: "Tool1,Tool2",
|
allowedTools: ["Tool1", "Tool2"],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const result = prepareContext(contextWithAllowedTools, "12345");
|
const result = prepareContext(contextWithAllowedTools, "12345");
|
||||||
|
|||||||
@@ -30,8 +30,8 @@ describe("checkContainsTrigger", () => {
|
|||||||
triggerPhrase: "/claude",
|
triggerPhrase: "/claude",
|
||||||
assigneeTrigger: "",
|
assigneeTrigger: "",
|
||||||
directPrompt: "Fix the bug in the login form",
|
directPrompt: "Fix the bug in the login form",
|
||||||
allowedTools: "",
|
allowedTools: [],
|
||||||
disallowedTools: "",
|
disallowedTools: [],
|
||||||
customInstructions: "",
|
customInstructions: "",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -56,8 +56,8 @@ describe("checkContainsTrigger", () => {
|
|||||||
triggerPhrase: "/claude",
|
triggerPhrase: "/claude",
|
||||||
assigneeTrigger: "",
|
assigneeTrigger: "",
|
||||||
directPrompt: "",
|
directPrompt: "",
|
||||||
allowedTools: "",
|
allowedTools: [],
|
||||||
disallowedTools: "",
|
disallowedTools: [],
|
||||||
customInstructions: "",
|
customInstructions: "",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -228,8 +228,8 @@ describe("checkContainsTrigger", () => {
|
|||||||
triggerPhrase: "@claude",
|
triggerPhrase: "@claude",
|
||||||
assigneeTrigger: "",
|
assigneeTrigger: "",
|
||||||
directPrompt: "",
|
directPrompt: "",
|
||||||
allowedTools: "",
|
allowedTools: [],
|
||||||
disallowedTools: "",
|
disallowedTools: [],
|
||||||
customInstructions: "",
|
customInstructions: "",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -255,8 +255,8 @@ describe("checkContainsTrigger", () => {
|
|||||||
triggerPhrase: "@claude",
|
triggerPhrase: "@claude",
|
||||||
assigneeTrigger: "",
|
assigneeTrigger: "",
|
||||||
directPrompt: "",
|
directPrompt: "",
|
||||||
allowedTools: "",
|
allowedTools: [],
|
||||||
disallowedTools: "",
|
disallowedTools: [],
|
||||||
customInstructions: "",
|
customInstructions: "",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -282,8 +282,8 @@ describe("checkContainsTrigger", () => {
|
|||||||
triggerPhrase: "@claude",
|
triggerPhrase: "@claude",
|
||||||
assigneeTrigger: "",
|
assigneeTrigger: "",
|
||||||
directPrompt: "",
|
directPrompt: "",
|
||||||
allowedTools: "",
|
allowedTools: [],
|
||||||
disallowedTools: "",
|
disallowedTools: [],
|
||||||
customInstructions: "",
|
customInstructions: "",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user