mirror of
https://github.com/anthropics/claude-code-action.git
synced 2026-01-23 15:04:13 +08:00
* feat: add agent mode for automation scenarios - Add agent mode that always triggers without checking for mentions - Implement Mode interface with support for mode-specific tool configuration - Add getAllowedTools() and getDisallowedTools() methods to Mode interface - Simplify tests by combining related test cases - Update documentation and examples to include agent mode - Fix TypeScript imports to prevent circular dependencies Agent mode is designed for automation and workflow_dispatch scenarios where Claude should always run without requiring trigger phrases. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * Minor update to readme (from @main to @beta) * Since workflow_dispatch isn't in the base action, update the examples accordingly * minor formatting issue * Update to say beta instead of main * Fix missed tracking comment to be false * add schedule & workflow dispatch paths. Also make prepare logic conditional * tests * Add test workflow for workflow_dispatch functionality * Update workflow to use correct branch reference * remove test workflow dispatch file * minor lint update * update workflow dispatch agent example * minor lint update * refactor: simplify prepare logic with mode-specific implementations * ensure tag mode can't work with workflow dispatch and schedule tasks * simplify: remove workflow_dispatch/schedule from create-prompt - Remove workflow_dispatch and schedule event handling from create-prompt since agent mode doesn't use the standard prompt generation flow - Enforce mode compatibility at selection time in the registry instead of runtime validation in tag mode - Add explanatory comment in agent mode about why prompt file is needed - Update tests to reflect simplified event handling This reduces code duplication and makes the separation between tag mode (entity-based events) and agent mode (automation events) clearer. * simplify PR by making agent mode only work with workflow dispatch and schedule events * remove unnecessary changes * remove unnecessary changes from PR - Revert update-comment-link.ts changes (agent mode doesn't use this) - Revert create-initial.ts changes (agent mode doesn't create comments) - Remove unused default-branch.ts file - Revert install-mcp-server.ts changes (agent mode uses minimal MCP) These files are only used by tag mode for entity-based events, not needed for workflow_dispatch/schedule support via agent mode. * fix: handle optional entityNumber for TypeScript - Add runtime checks in files that require entityNumber - These files are only used by tag mode which always has entityNumber - Agent mode (workflow_dispatch/schedule) doesn't use these files * linting update * refactor: implement discriminated unions for GitHub contexts Split ParsedGitHubContext into entity-specific and automation contexts: - ParsedGitHubContext: For entity events (issues/PRs) with required entityNumber and isPR - AutomationContext: For workflow_dispatch/schedule events without entity fields - GitHubContext: Union type for all contexts This eliminates ~20 null checks throughout the codebase and provides better type safety. Entity-specific code paths are now guaranteed to have the required fields. Co-Authored-By: Claude <noreply@anthropic.com> * update comment * More robust type checking * refactor: improve discriminated union implementation based on review feedback - Use eventName checks instead of 'in' operator for more robust type guards - Remove unnecessary type assertions - TypeScript's control flow analysis works correctly - Remove redundant runtime checks for entityNumber and isPR - Simplify code by using context directly after type guard Co-Authored-By: Claude <noreply@anthropic.com> * some structural simplification * refactor: further simplify discriminated union implementation - Add event name constants to reduce duplication - Derive EntityEventName and AutomationEventName types from constants - Use isAutomationContext consistently in agent mode and registry - Simplify parseGitHubContext by removing redundant type assertions - Extract payload casts to variables for cleaner code Co-Authored-By: Claude <noreply@anthropic.com> * bun format * specify the type * minor linting update again --------- Co-authored-by: km-anthropic <km-anthropic@users.noreply.github.com> Co-authored-by: Claude <noreply@anthropic.com>
112 lines
3.5 KiB
TypeScript
112 lines
3.5 KiB
TypeScript
#!/usr/bin/env bun
|
|
|
|
/**
|
|
* Create the initial tracking comment when Claude Code starts working
|
|
* This comment shows the working status and includes a link to the job run
|
|
*/
|
|
|
|
import { appendFileSync } from "fs";
|
|
import { createJobRunLink, createCommentBody } from "./common";
|
|
import {
|
|
isPullRequestReviewCommentEvent,
|
|
isPullRequestEvent,
|
|
type ParsedGitHubContext,
|
|
} from "../../context";
|
|
import type { Octokit } from "@octokit/rest";
|
|
|
|
const CLAUDE_APP_BOT_ID = 209825114;
|
|
|
|
export async function createInitialComment(
|
|
octokit: Octokit,
|
|
context: ParsedGitHubContext,
|
|
) {
|
|
const { owner, repo } = context.repository;
|
|
|
|
const jobRunLink = createJobRunLink(owner, repo, context.runId);
|
|
const initialBody = createCommentBody(jobRunLink);
|
|
|
|
try {
|
|
let response;
|
|
|
|
if (
|
|
context.inputs.useStickyComment &&
|
|
context.isPR &&
|
|
isPullRequestEvent(context)
|
|
) {
|
|
const comments = await octokit.rest.issues.listComments({
|
|
owner,
|
|
repo,
|
|
issue_number: context.entityNumber,
|
|
});
|
|
const existingComment = comments.data.find((comment) => {
|
|
const idMatch = comment.user?.id === CLAUDE_APP_BOT_ID;
|
|
const botNameMatch =
|
|
comment.user?.type === "Bot" &&
|
|
comment.user?.login.toLowerCase().includes("claude");
|
|
const bodyMatch = comment.body === initialBody;
|
|
|
|
return idMatch || botNameMatch || bodyMatch;
|
|
});
|
|
if (existingComment) {
|
|
response = await octokit.rest.issues.updateComment({
|
|
owner,
|
|
repo,
|
|
comment_id: existingComment.id,
|
|
body: initialBody,
|
|
});
|
|
} else {
|
|
// Create new comment if no existing one found
|
|
response = await octokit.rest.issues.createComment({
|
|
owner,
|
|
repo,
|
|
issue_number: context.entityNumber,
|
|
body: initialBody,
|
|
});
|
|
}
|
|
} else if (isPullRequestReviewCommentEvent(context)) {
|
|
// Only use createReplyForReviewComment if it's a PR review comment AND we have a comment_id
|
|
response = await octokit.rest.pulls.createReplyForReviewComment({
|
|
owner,
|
|
repo,
|
|
pull_number: context.entityNumber,
|
|
comment_id: context.payload.comment.id,
|
|
body: initialBody,
|
|
});
|
|
} else {
|
|
// For all other cases (issues, issue comments, or missing comment_id)
|
|
response = await octokit.rest.issues.createComment({
|
|
owner,
|
|
repo,
|
|
issue_number: context.entityNumber,
|
|
body: initialBody,
|
|
});
|
|
}
|
|
|
|
// Output the comment ID for downstream steps using GITHUB_OUTPUT
|
|
const githubOutput = process.env.GITHUB_OUTPUT!;
|
|
appendFileSync(githubOutput, `claude_comment_id=${response.data.id}\n`);
|
|
console.log(`✅ Created initial comment with ID: ${response.data.id}`);
|
|
return response.data;
|
|
} catch (error) {
|
|
console.error("Error in initial comment:", error);
|
|
|
|
// Always fall back to regular issue comment if anything fails
|
|
try {
|
|
const response = await octokit.rest.issues.createComment({
|
|
owner,
|
|
repo,
|
|
issue_number: context.entityNumber,
|
|
body: initialBody,
|
|
});
|
|
|
|
const githubOutput = process.env.GITHUB_OUTPUT!;
|
|
appendFileSync(githubOutput, `claude_comment_id=${response.data.id}\n`);
|
|
console.log(`✅ Created fallback comment with ID: ${response.data.id}`);
|
|
return response.data;
|
|
} catch (fallbackError) {
|
|
console.error("Error creating fallback comment:", fallbackError);
|
|
throw fallbackError;
|
|
}
|
|
}
|
|
}
|