From 859e93f18ed780677d0fb2efcd8ffeb274a8f136 Mon Sep 17 00:00:00 2001 From: km-anthropic Date: Tue, 29 Jul 2025 09:38:00 -0700 Subject: [PATCH] ensure tag mode can't work with workflow dispatch and schedule tasks --- src/create-prompt/index.ts | 83 +++----------------------------------- src/modes/tag/index.ts | 11 +++++ test/create-prompt.test.ts | 72 --------------------------------- 3 files changed, 17 insertions(+), 149 deletions(-) diff --git a/src/create-prompt/index.ts b/src/create-prompt/index.ts index d75cf4b..14a7220 100644 --- a/src/create-prompt/index.ts +++ b/src/create-prompt/index.ts @@ -449,12 +449,11 @@ export function getEventTypeAndContext(envVars: PreparedContext): { function getCommitInstructions( eventData: EventData, - githubData: FetchDataResult | null, + githubData: FetchDataResult, context: PreparedContext, useCommitSigning: boolean, ): string { const coAuthorLine = - githubData && (githubData.triggerDisplayName ?? context.triggerUsername !== "Unknown") ? `Co-authored-by: ${githubData.triggerDisplayName ?? context.triggerUsername} <${context.triggerUsername}@users.noreply.github.com>` : ""; @@ -509,26 +508,8 @@ function getCommitInstructions( function substitutePromptVariables( template: string, context: PreparedContext, - githubData: FetchDataResult | null, + githubData: FetchDataResult, ): string { - // Handle automation events without GitHub data - if (!githubData) { - const { eventData } = context; - const variables: Record = { - EVENT_TYPE: eventData.eventName, - REPOSITORY: context.repository, - TRIGGER_USERNAME: context.triggerUsername ?? "automation", - CURRENT_BRANCH: eventData.claudeBranch || eventData.baseBranch || "main", - BASE_BRANCH: eventData.baseBranch || "main", - }; - - return Object.entries(variables).reduce( - (prompt, [key, value]) => - prompt.replace(new RegExp(`{{${key}}}`, "g"), value), - template, - ); - } - const { contextData, comments, reviewData, changedFilesWithSHA } = githubData; const { eventData } = context; @@ -589,7 +570,7 @@ function substitutePromptVariables( export function generatePrompt( context: PreparedContext, - githubData: FetchDataResult | null, + githubData: FetchDataResult, useCommitSigning: boolean, ): string { if (context.overridePrompt) { @@ -601,58 +582,6 @@ export function generatePrompt( } const { eventData } = context; - - // Handle automation events that don't have GitHub data - if (!githubData) { - // For automation events, we have minimal context - const { eventType, triggerContext } = getEventTypeAndContext(context); - - let promptContent = `You are Claude, an AI assistant designed to help with GitHub ${eventData.eventName === "workflow_dispatch" ? "workflow dispatch" : "scheduled automation"} tasks. Think carefully as you analyze the context and respond appropriately. Here's the context for your current task: - - -Repository: ${context.repository} -Event Type: ${eventData.eventName} -Current Branch: ${eventData.claudeBranch || eventData.baseBranch || "main"} -Base Branch: ${eventData.baseBranch || "main"} -Actor: ${context.triggerUsername ?? "automation"} - - -${eventType} -false -${triggerContext} -${context.repository} -${context.triggerUsername ?? "automation"} -${ - context.directPrompt - ? ` -IMPORTANT: The following are direct instructions from the automation workflow: - -${sanitizeContent(context.directPrompt)} -` - : "" -} - - -You have been triggered by an automated workflow. Follow these guidelines: - -1. **Context**: You are running in an automated context without a specific issue or PR. -2. **Branch**: You are currently on the ${eventData.claudeBranch || eventData.baseBranch || "main"} branch. -3. **Tools**: You have access to file system and Git tools to make changes. -${ - useCommitSigning - ? "4. **Commits**: Use the MCP file operations server for signed commits." - : "4. **Commits**: You can commit changes directly using Git." -} -5. **Scope**: Focus on the task described${context.directPrompt ? " in the direct_prompt above" : ""}. - -Please proceed with the automated task. - - -${context.customInstructions || ""}`; - - return promptContent; - } - const { contextData, comments, @@ -663,7 +592,7 @@ ${context.customInstructions || ""}`; const { eventType, triggerContext } = getEventTypeAndContext(context); - const formattedContext = formatContext(contextData, eventData.isPR ?? false); + const formattedContext = formatContext(contextData, eventData.isPR!); const formattedComments = formatComments(comments, imageUrlMap); const formattedReviewComments = eventData.isPR ? formatReviewComments(reviewData, imageUrlMap) @@ -709,7 +638,7 @@ ${eventData.isPR ? formattedChangedFiles || "No files changed" : ""} ${imagesInfo} ${eventType} -${(eventData.isPR ?? false) ? "true" : "false"} +${eventData.isPR ? "true" : "false"} ${triggerContext} ${context.repository} ${getEntityNumberXml(eventData)} @@ -906,7 +835,7 @@ f. If you are unable to complete certain steps, such as running a linter or test export async function createPrompt( mode: Mode, modeContext: ModeContext, - githubData: FetchDataResult | null, + githubData: FetchDataResult, context: ParsedGitHubContext, ) { try { diff --git a/src/modes/tag/index.ts b/src/modes/tag/index.ts index 5731c94..40ecd71 100644 --- a/src/modes/tag/index.ts +++ b/src/modes/tag/index.ts @@ -53,6 +53,17 @@ export const tagMode: Mode = { }: ModeOptions): Promise { // Tag mode handles entity-based events (issues, PRs, comments) + // Validate this mode can handle the event + if ( + context.eventName === "workflow_dispatch" || + context.eventName === "schedule" + ) { + throw new Error( + `Tag mode cannot handle ${context.eventName} events. ` + + `Use 'agent' mode for automation events.`, + ); + } + // Check if actor is human await checkHumanActor(octokit.rest, context); diff --git a/test/create-prompt.test.ts b/test/create-prompt.test.ts index aaa7cb2..fe5febd 100644 --- a/test/create-prompt.test.ts +++ b/test/create-prompt.test.ts @@ -713,78 +713,6 @@ describe("generatePrompt", () => { ); }); - test("should generate prompt for workflow_dispatch event with null githubData", () => { - const envVars: PreparedContext = { - repository: "owner/repo", - triggerPhrase: "@claude", - eventData: { - eventName: "workflow_dispatch", - isPR: false, - baseBranch: "main", - }, - }; - - const prompt = generatePrompt(envVars, null, false); - - expect(prompt).toContain("WORKFLOW_DISPATCH"); - expect(prompt).toContain("false"); - expect(prompt).toContain( - "workflow dispatch event", - ); - expect(prompt).toContain( - "You are running in an automated context without a specific issue or PR", - ); - expect(prompt).not.toContain(""); - expect(prompt).not.toContain(""); - }); - - test("should generate prompt for schedule event with null githubData", () => { - const envVars: PreparedContext = { - repository: "owner/repo", - triggerPhrase: "@claude", - triggerUsername: "github-actions[bot]", - eventData: { - eventName: "schedule", - isPR: false, - baseBranch: "main", - }, - }; - - const prompt = generatePrompt(envVars, null, false); - - expect(prompt).toContain("SCHEDULE"); - expect(prompt).toContain("false"); - expect(prompt).toContain( - "scheduled automation event", - ); - expect(prompt).toContain("scheduled automation"); - expect(prompt).toContain( - "github-actions[bot]", - ); - }); - - test("should include direct prompt for automation events", () => { - const envVars: PreparedContext = { - repository: "owner/repo", - triggerPhrase: "@claude", - directPrompt: "Run daily maintenance tasks", - eventData: { - eventName: "workflow_dispatch", - isPR: false, - baseBranch: "main", - }, - }; - - const prompt = generatePrompt(envVars, null, false); - - expect(prompt).toContain(""); - expect(prompt).toContain("Run daily maintenance tasks"); - expect(prompt).toContain(""); - expect(prompt).toContain( - "IMPORTANT: The following are direct instructions from the automation workflow", - ); - }); - test("should handle pull_request event on closed PR with new branch", () => { const envVars: PreparedContext = { repository: "owner/repo",