Compare commits

...

7 Commits

Author SHA1 Message Date
km-anthropic
8f551b358e Add override prompt variable (#301)
* Add override prompt variable

* create test

* Fix typechecks

* remove use of `any` for additional type-safety

---------

Co-authored-by: km-anthropic <km-anthropic@users.noreply.github.com>
2025-07-21 17:41:25 -07:00
GitHub Actions
0d8a8fe1ac chore: bump Claude Code version to 1.0.57 2025-07-22 00:25:13 +00:00
Ashwin Bhat
93df09fd88 fix: checkout base branch before creating new branches (#311)
- Fix bug where base_branch parameter was not being respected
- Add git fetch and checkout of source branch before creating new branch
- Ensures new branches are created from specified base_branch instead of current HEAD
- Fixes issue #268

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-authored-by: Claude <noreply@anthropic.com>
2025-07-19 08:26:59 -07:00
Ashwin Bhat
d290268f83 fix: run Claude from workflow directory instead of base-action directory (#312)
Changed the action to cd back to the original directory after installing
dependencies, ensuring Claude runs in the context of the user's workflow
rather than the base-action subdirectory.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-authored-by: Claude <noreply@anthropic.com>
2025-07-19 08:26:23 -07:00
Ashwin Bhat
d69f61e377 fix: conditionally show Bash limitation based on commit signing setting (#310)
- Remove 'Run arbitrary Bash commands' from limitations when commit signing is disabled
- This avoids confusion since git commands ARE allowed via Bash when not using commit signing
- The prompt now accurately reflects what Claude can do based on the useCommitSigning parameter
2025-07-19 08:18:05 -07:00
Gray Choi
de86beb3ae fix: add model parameter support to base-action (#307)
- Add model field to ClaudeOptions type
- Pass ANTHROPIC_MODEL env var to runClaude function
- Handle --model argument in prepareRunConfig

This allows the model specified in action.yml to be properly passed
to the Claude CLI command.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-authored-by: Claude <noreply@anthropic.com>
2025-07-19 07:48:29 -07:00
GitHub Actions
5c420d2402 chore: bump Claude Code version to 1.0.56 2025-07-19 00:07:08 +00:00
14 changed files with 277 additions and 6 deletions

View File

@@ -170,6 +170,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\* | - |
| `claude_code_oauth_token` | Claude Code OAuth token (alternative to anthropic_api_key) | No\* | - | | `claude_code_oauth_token` | Claude Code OAuth token (alternative to anthropic_api_key) | 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 | - |
| `override_prompt` | Complete replacement of Claude's prompt with custom template (supports variable substitution) | No | - |
| `base_branch` | The base branch to use for creating new branches (e.g., 'main', 'develop') | No | - | | `base_branch` | The base branch to use for creating new branches (e.g., 'main', 'develop') | No | - |
| `max_turns` | Maximum number of conversation turns Claude can take (limits back-and-forth exchanges) | 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` |
@@ -395,6 +396,36 @@ jobs:
Perfect for automatically reviewing PRs from new team members, external contributors, or specific developers who need extra guidance. Perfect for automatically reviewing PRs from new team members, external contributors, or specific developers who need extra guidance.
#### Custom Prompt Templates
Use `override_prompt` for complete control over Claude's behavior with variable substitution:
```yaml
- uses: anthropics/claude-code-action@beta
with:
override_prompt: |
Analyze PR #$PR_NUMBER in $REPOSITORY for security vulnerabilities.
Changed files:
$CHANGED_FILES
Focus on:
- SQL injection risks
- XSS vulnerabilities
- Authentication bypasses
- Exposed secrets or credentials
Provide severity ratings (Critical/High/Medium/Low) for any issues found.
```
The `override_prompt` feature supports these variables:
- `$REPOSITORY`, `$PR_NUMBER`, `$ISSUE_NUMBER`
- `$PR_TITLE`, `$ISSUE_TITLE`, `$PR_BODY`, `$ISSUE_BODY`
- `$PR_COMMENTS`, `$ISSUE_COMMENTS`, `$REVIEW_COMMENTS`
- `$CHANGED_FILES`, `$TRIGGER_COMMENT`, `$TRIGGER_USERNAME`
- `$BRANCH_NAME`, `$BASE_BRANCH`, `$EVENT_TYPE`, `$IS_PR`
## How It Works ## How It Works
1. **Trigger Detection**: Listens for comments containing the trigger phrase (default: `@claude`) or issue assignment to a specific user 1. **Trigger Detection**: Listens for comments containing the trigger phrase (default: `@claude`) or issue assignment to a specific user

View File

@@ -50,6 +50,10 @@ inputs:
description: "Direct instruction for Claude (bypasses normal trigger detection)" description: "Direct instruction for Claude (bypasses normal trigger detection)"
required: false required: false
default: "" default: ""
override_prompt:
description: "Complete replacement of Claude's prompt with custom template (supports variable substitution)"
required: false
default: ""
mcp_config: mcp_config:
description: "Additional MCP configuration (JSON string) that merges with the built-in GitHub MCP servers" description: "Additional MCP configuration (JSON string) that merges with the built-in GitHub MCP servers"
additional_permissions: additional_permissions:
@@ -142,6 +146,7 @@ runs:
DISALLOWED_TOOLS: ${{ inputs.disallowed_tools }} DISALLOWED_TOOLS: ${{ inputs.disallowed_tools }}
CUSTOM_INSTRUCTIONS: ${{ inputs.custom_instructions }} CUSTOM_INSTRUCTIONS: ${{ inputs.custom_instructions }}
DIRECT_PROMPT: ${{ inputs.direct_prompt }} DIRECT_PROMPT: ${{ inputs.direct_prompt }}
OVERRIDE_PROMPT: ${{ inputs.override_prompt }}
MCP_CONFIG: ${{ inputs.mcp_config }} MCP_CONFIG: ${{ inputs.mcp_config }}
OVERRIDE_GITHUB_TOKEN: ${{ inputs.github_token }} OVERRIDE_GITHUB_TOKEN: ${{ inputs.github_token }}
GITHUB_RUN_ID: ${{ github.run_id }} GITHUB_RUN_ID: ${{ github.run_id }}
@@ -188,12 +193,13 @@ runs:
shell: bash shell: bash
run: | run: |
# Install Claude Code globally # Install Claude Code globally
npm install -g @anthropic-ai/claude-code@1.0.53 npm install -g @anthropic-ai/claude-code@1.0.57
# Run the base-action # Run the base-action
cd ${GITHUB_ACTION_PATH}/base-action cd ${GITHUB_ACTION_PATH}/base-action
bun install bun install
bun run src/index.ts cd -
bun run ${GITHUB_ACTION_PATH}/base-action/src/index.ts
env: env:
# Base-action inputs # Base-action inputs
CLAUDE_CODE_ACTION: "1" CLAUDE_CODE_ACTION: "1"

View File

@@ -115,7 +115,7 @@ runs:
- name: Install Claude Code - name: Install Claude Code
shell: bash shell: bash
run: npm install -g @anthropic-ai/claude-code@1.0.53 run: npm install -g @anthropic-ai/claude-code@1.0.57
- name: Run Claude Code Action - name: Run Claude Code Action
shell: bash shell: bash

View File

@@ -26,6 +26,7 @@ async function run() {
appendSystemPrompt: process.env.INPUT_APPEND_SYSTEM_PROMPT, appendSystemPrompt: process.env.INPUT_APPEND_SYSTEM_PROMPT,
claudeEnv: process.env.INPUT_CLAUDE_ENV, claudeEnv: process.env.INPUT_CLAUDE_ENV,
fallbackModel: process.env.INPUT_FALLBACK_MODEL, fallbackModel: process.env.INPUT_FALLBACK_MODEL,
model: process.env.ANTHROPIC_MODEL,
}); });
} catch (error) { } catch (error) {
core.setFailed(`Action failed with error: ${error}`); core.setFailed(`Action failed with error: ${error}`);

View File

@@ -21,6 +21,7 @@ export type ClaudeOptions = {
claudeEnv?: string; claudeEnv?: string;
fallbackModel?: string; fallbackModel?: string;
timeoutMinutes?: string; timeoutMinutes?: string;
model?: string;
}; };
type PreparedConfig = { type PreparedConfig = {
@@ -94,6 +95,9 @@ export function prepareRunConfig(
if (options.fallbackModel) { if (options.fallbackModel) {
claudeArgs.push("--fallback-model", options.fallbackModel); claudeArgs.push("--fallback-model", options.fallbackModel);
} }
if (options.model) {
claudeArgs.push("--model", options.model);
}
if (options.timeoutMinutes) { if (options.timeoutMinutes) {
const timeoutMinutesNum = parseInt(options.timeoutMinutes, 10); const timeoutMinutesNum = parseInt(options.timeoutMinutes, 10);
if (isNaN(timeoutMinutesNum) || timeoutMinutesNum <= 0) { if (isNaN(timeoutMinutesNum) || timeoutMinutesNum <= 0) {

View File

@@ -120,6 +120,7 @@ export function prepareContext(
const allowedTools = context.inputs.allowedTools; const allowedTools = context.inputs.allowedTools;
const disallowedTools = context.inputs.disallowedTools; const disallowedTools = context.inputs.disallowedTools;
const directPrompt = context.inputs.directPrompt; const directPrompt = context.inputs.directPrompt;
const overridePrompt = context.inputs.overridePrompt;
const isPR = context.isPR; const isPR = context.isPR;
// Get PR/Issue number from entityNumber // Get PR/Issue number from entityNumber
@@ -158,6 +159,7 @@ export function prepareContext(
disallowedTools: disallowedTools.join(","), disallowedTools: disallowedTools.join(","),
}), }),
...(directPrompt && { directPrompt }), ...(directPrompt && { directPrompt }),
...(overridePrompt && { overridePrompt }),
...(claudeBranch && { claudeBranch }), ...(claudeBranch && { claudeBranch }),
}; };
@@ -460,11 +462,76 @@ function getCommitInstructions(
} }
} }
function substitutePromptVariables(
template: string,
context: PreparedContext,
githubData: FetchDataResult,
): string {
const { contextData, comments, reviewData, changedFilesWithSHA } = githubData;
const { eventData } = context;
const variables: Record<string, string> = {
REPOSITORY: context.repository,
PR_NUMBER:
eventData.isPR && "prNumber" in eventData ? eventData.prNumber : "",
ISSUE_NUMBER:
!eventData.isPR && "issueNumber" in eventData
? eventData.issueNumber
: "",
PR_TITLE: eventData.isPR && contextData?.title ? contextData.title : "",
ISSUE_TITLE: !eventData.isPR && contextData?.title ? contextData.title : "",
PR_BODY: eventData.isPR && contextData?.body ? contextData.body : "",
ISSUE_BODY: !eventData.isPR && contextData?.body ? contextData.body : "",
PR_COMMENTS: eventData.isPR
? formatComments(comments, githubData.imageUrlMap)
: "",
ISSUE_COMMENTS: !eventData.isPR
? formatComments(comments, githubData.imageUrlMap)
: "",
REVIEW_COMMENTS: eventData.isPR
? formatReviewComments(reviewData, githubData.imageUrlMap)
: "",
CHANGED_FILES: eventData.isPR
? formatChangedFilesWithSHA(changedFilesWithSHA)
: "",
TRIGGER_COMMENT: "commentBody" in eventData ? eventData.commentBody : "",
TRIGGER_USERNAME: context.triggerUsername || "",
BRANCH_NAME:
"claudeBranch" in eventData && eventData.claudeBranch
? eventData.claudeBranch
: "baseBranch" in eventData && eventData.baseBranch
? eventData.baseBranch
: "",
BASE_BRANCH:
"baseBranch" in eventData && eventData.baseBranch
? eventData.baseBranch
: "",
EVENT_TYPE: eventData.eventName,
IS_PR: eventData.isPR ? "true" : "false",
};
let result = template;
for (const [key, value] of Object.entries(variables)) {
const regex = new RegExp(`\\$${key}`, "g");
result = result.replace(regex, value);
}
return result;
}
export function generatePrompt( export function generatePrompt(
context: PreparedContext, context: PreparedContext,
githubData: FetchDataResult, githubData: FetchDataResult,
useCommitSigning: boolean, useCommitSigning: boolean,
): string { ): string {
if (context.overridePrompt) {
return substitutePromptVariables(
context.overridePrompt,
context,
githubData,
);
}
const { const {
contextData, contextData,
comments, comments,
@@ -694,8 +761,7 @@ What You CANNOT Do:
- Submit formal GitHub PR reviews - Submit formal GitHub PR reviews
- Approve pull requests (for security reasons) - Approve pull requests (for security reasons)
- Post multiple comments (you only update your initial comment) - Post multiple comments (you only update your initial comment)
- Execute commands outside the repository context - Execute commands outside the repository context${useCommitSigning ? "\n- Run arbitrary Bash commands (unless explicitly allowed via allowed_tools configuration)" : ""}
- Run arbitrary Bash commands (unless explicitly allowed via allowed_tools configuration)
- Perform branch operations (cannot merge branches, rebase, or perform other git operations beyond pushing commits) - Perform branch operations (cannot merge branches, rebase, or perform other git operations beyond pushing commits)
- Modify files in the .github/workflows directory (GitHub App permissions do not allow workflow modifications) - Modify files in the .github/workflows directory (GitHub App permissions do not allow workflow modifications)
- View CI/CD results or workflow run outputs (cannot access GitHub Actions logs or test results) - View CI/CD results or workflow run outputs (cannot access GitHub Actions logs or test results)

View File

@@ -7,6 +7,7 @@ export type CommonFields = {
allowedTools?: string; allowedTools?: string;
disallowedTools?: string; disallowedTools?: string;
directPrompt?: string; directPrompt?: string;
overridePrompt?: string;
}; };
type PullRequestReviewCommentEvent = { type PullRequestReviewCommentEvent = {

View File

@@ -34,6 +34,7 @@ export type ParsedGitHubContext = {
disallowedTools: string[]; disallowedTools: string[];
customInstructions: string; customInstructions: string;
directPrompt: string; directPrompt: string;
overridePrompt: string;
baseBranch?: string; baseBranch?: string;
branchPrefix: string; branchPrefix: string;
useStickyComment: boolean; useStickyComment: boolean;
@@ -63,6 +64,7 @@ export function parseGitHubContext(): ParsedGitHubContext {
disallowedTools: parseMultilineInput(process.env.DISALLOWED_TOOLS ?? ""), disallowedTools: parseMultilineInput(process.env.DISALLOWED_TOOLS ?? ""),
customInstructions: process.env.CUSTOM_INSTRUCTIONS ?? "", customInstructions: process.env.CUSTOM_INSTRUCTIONS ?? "",
directPrompt: process.env.DIRECT_PROMPT ?? "", directPrompt: process.env.DIRECT_PROMPT ?? "",
overridePrompt: process.env.OVERRIDE_PROMPT ?? "",
baseBranch: process.env.BASE_BRANCH, baseBranch: process.env.BASE_BRANCH,
branchPrefix: process.env.BRANCH_PREFIX ?? "claude/", branchPrefix: process.env.BRANCH_PREFIX ?? "claude/",
useStickyComment: process.env.USE_STICKY_COMMENT === "true", useStickyComment: process.env.USE_STICKY_COMMENT === "true",

View File

@@ -116,6 +116,11 @@ export async function setupBranch(
`Branch name generated: ${newBranch} (will be created by file ops server on first commit)`, `Branch name generated: ${newBranch} (will be created by file ops server on first commit)`,
); );
// Ensure we're on the source branch
console.log(`Fetching and checking out source branch: ${sourceBranch}`);
await $`git fetch origin ${sourceBranch} --depth=1`;
await $`git checkout ${sourceBranch}`;
// Set outputs for GitHub Actions // Set outputs for GitHub Actions
core.setOutput("CLAUDE_BRANCH", newBranch); core.setOutput("CLAUDE_BRANCH", newBranch);
core.setOutput("BASE_BRANCH", sourceBranch); core.setOutput("BASE_BRANCH", sourceBranch);
@@ -131,7 +136,12 @@ export async function setupBranch(
`Creating local branch ${newBranch} for ${entityType} #${entityNumber} from source branch: ${sourceBranch}...`, `Creating local branch ${newBranch} for ${entityType} #${entityNumber} from source branch: ${sourceBranch}...`,
); );
// Create and checkout the new branch locally // Fetch and checkout the source branch first to ensure we branch from the correct base
console.log(`Fetching and checking out source branch: ${sourceBranch}`);
await $`git fetch origin ${sourceBranch} --depth=1`;
await $`git checkout ${sourceBranch}`;
// Create and checkout the new branch from the source branch
await $`git checkout -b ${newBranch}`; await $`git checkout -b ${newBranch}`;
console.log( console.log(

View File

@@ -322,6 +322,148 @@ describe("generatePrompt", () => {
expect(prompt).toContain("CUSTOM INSTRUCTIONS:\nAlways use TypeScript"); expect(prompt).toContain("CUSTOM INSTRUCTIONS:\nAlways use TypeScript");
}); });
test("should use override_prompt when provided", () => {
const envVars: PreparedContext = {
repository: "owner/repo",
claudeCommentId: "12345",
triggerPhrase: "@claude",
overridePrompt: "Simple prompt for $REPOSITORY PR #$PR_NUMBER",
eventData: {
eventName: "pull_request",
eventAction: "opened",
isPR: true,
prNumber: "123",
},
};
const prompt = generatePrompt(envVars, mockGitHubData, false);
expect(prompt).toBe("Simple prompt for owner/repo PR #123");
expect(prompt).not.toContain("You are Claude, an AI assistant");
});
test("should substitute all variables in override_prompt", () => {
const envVars: PreparedContext = {
repository: "test/repo",
claudeCommentId: "12345",
triggerPhrase: "@claude",
triggerUsername: "john-doe",
overridePrompt: `Repository: $REPOSITORY
PR: $PR_NUMBER
Title: $PR_TITLE
Body: $PR_BODY
Comments: $PR_COMMENTS
Review Comments: $REVIEW_COMMENTS
Changed Files: $CHANGED_FILES
Trigger Comment: $TRIGGER_COMMENT
Username: $TRIGGER_USERNAME
Branch: $BRANCH_NAME
Base: $BASE_BRANCH
Event: $EVENT_TYPE
Is PR: $IS_PR`,
eventData: {
eventName: "pull_request_review_comment",
isPR: true,
prNumber: "456",
commentBody: "Please review this code",
claudeBranch: "feature-branch",
baseBranch: "main",
},
};
const prompt = generatePrompt(envVars, mockGitHubData, false);
expect(prompt).toContain("Repository: test/repo");
expect(prompt).toContain("PR: 456");
expect(prompt).toContain("Title: Test PR");
expect(prompt).toContain("Body: This is a test PR");
expect(prompt).toContain("Comments: ");
expect(prompt).toContain("Review Comments: ");
expect(prompt).toContain("Changed Files: ");
expect(prompt).toContain("Trigger Comment: Please review this code");
expect(prompt).toContain("Username: john-doe");
expect(prompt).toContain("Branch: feature-branch");
expect(prompt).toContain("Base: main");
expect(prompt).toContain("Event: pull_request_review_comment");
expect(prompt).toContain("Is PR: true");
});
test("should handle override_prompt for issues", () => {
const envVars: PreparedContext = {
repository: "owner/repo",
claudeCommentId: "12345",
triggerPhrase: "@claude",
overridePrompt: "Issue #$ISSUE_NUMBER: $ISSUE_TITLE in $REPOSITORY",
eventData: {
eventName: "issues",
eventAction: "opened",
isPR: false,
issueNumber: "789",
baseBranch: "main",
claudeBranch: "claude/issue-789-20240101-1200",
},
};
const issueGitHubData = {
...mockGitHubData,
contextData: {
title: "Bug: Login form broken",
body: "The login form is not working",
author: { login: "testuser" },
state: "OPEN",
createdAt: "2023-01-01T00:00:00Z",
comments: {
nodes: [],
},
},
};
const prompt = generatePrompt(envVars, issueGitHubData, false);
expect(prompt).toBe("Issue #789: Bug: Login form broken in owner/repo");
});
test("should handle empty values in override_prompt substitution", () => {
const envVars: PreparedContext = {
repository: "owner/repo",
claudeCommentId: "12345",
triggerPhrase: "@claude",
overridePrompt:
"PR: $PR_NUMBER, Issue: $ISSUE_NUMBER, Comment: $TRIGGER_COMMENT",
eventData: {
eventName: "pull_request",
eventAction: "opened",
isPR: true,
prNumber: "123",
},
};
const prompt = generatePrompt(envVars, mockGitHubData, false);
expect(prompt).toBe("PR: 123, Issue: , Comment: ");
});
test("should not substitute variables when override_prompt is not provided", () => {
const envVars: PreparedContext = {
repository: "owner/repo",
claudeCommentId: "12345",
triggerPhrase: "@claude",
eventData: {
eventName: "issues",
eventAction: "opened",
isPR: false,
issueNumber: "123",
baseBranch: "main",
claudeBranch: "claude/issue-123-20240101-1200",
},
};
const prompt = generatePrompt(envVars, mockGitHubData, false);
expect(prompt).toContain("You are Claude, an AI assistant");
expect(prompt).toContain("<event_type>ISSUE_CREATED</event_type>");
});
test("should include trigger username when provided", () => { test("should include trigger username when provided", () => {
const envVars: PreparedContext = { const envVars: PreparedContext = {
repository: "owner/repo", repository: "owner/repo",

View File

@@ -31,6 +31,7 @@ describe("prepareMcpConfig", () => {
disallowedTools: [], disallowedTools: [],
customInstructions: "", customInstructions: "",
directPrompt: "", directPrompt: "",
overridePrompt: "",
branchPrefix: "", branchPrefix: "",
useStickyComment: false, useStickyComment: false,
additionalPermissions: new Map(), additionalPermissions: new Map(),

View File

@@ -16,6 +16,7 @@ const defaultInputs = {
disallowedTools: [] as string[], disallowedTools: [] as string[],
customInstructions: "", customInstructions: "",
directPrompt: "", directPrompt: "",
overridePrompt: "",
useBedrock: false, useBedrock: false,
useVertex: false, useVertex: false,
timeoutMinutes: 30, timeoutMinutes: 30,

View File

@@ -67,6 +67,7 @@ describe("checkWritePermissions", () => {
disallowedTools: [], disallowedTools: [],
customInstructions: "", customInstructions: "",
directPrompt: "", directPrompt: "",
overridePrompt: "",
branchPrefix: "claude/", branchPrefix: "claude/",
useStickyComment: false, useStickyComment: false,
additionalPermissions: new Map(), additionalPermissions: new Map(),

View File

@@ -32,6 +32,7 @@ describe("checkContainsTrigger", () => {
assigneeTrigger: "", assigneeTrigger: "",
labelTrigger: "", labelTrigger: "",
directPrompt: "Fix the bug in the login form", directPrompt: "Fix the bug in the login form",
overridePrompt: "",
allowedTools: [], allowedTools: [],
disallowedTools: [], disallowedTools: [],
customInstructions: "", customInstructions: "",
@@ -63,6 +64,7 @@ describe("checkContainsTrigger", () => {
assigneeTrigger: "", assigneeTrigger: "",
labelTrigger: "", labelTrigger: "",
directPrompt: "", directPrompt: "",
overridePrompt: "",
allowedTools: [], allowedTools: [],
disallowedTools: [], disallowedTools: [],
customInstructions: "", customInstructions: "",
@@ -278,6 +280,7 @@ describe("checkContainsTrigger", () => {
assigneeTrigger: "", assigneeTrigger: "",
labelTrigger: "", labelTrigger: "",
directPrompt: "", directPrompt: "",
overridePrompt: "",
allowedTools: [], allowedTools: [],
disallowedTools: [], disallowedTools: [],
customInstructions: "", customInstructions: "",
@@ -310,6 +313,7 @@ describe("checkContainsTrigger", () => {
assigneeTrigger: "", assigneeTrigger: "",
labelTrigger: "", labelTrigger: "",
directPrompt: "", directPrompt: "",
overridePrompt: "",
allowedTools: [], allowedTools: [],
disallowedTools: [], disallowedTools: [],
customInstructions: "", customInstructions: "",
@@ -342,6 +346,7 @@ describe("checkContainsTrigger", () => {
assigneeTrigger: "", assigneeTrigger: "",
labelTrigger: "", labelTrigger: "",
directPrompt: "", directPrompt: "",
overridePrompt: "",
allowedTools: [], allowedTools: [],
disallowedTools: [], disallowedTools: [],
customInstructions: "", customInstructions: "",