Compare commits

..

5 Commits

Author SHA1 Message Date
guro
7680c1d501 feat: add workflow_dispatch trigger with cloudflare tunnel token input
- Add manual trigger support for GitHub Actions UI
- Include cloudflare_tunnel_token and direct_prompt inputs
- Set agent mode for workflow_dispatch events
- Enable manual execution of Claude Code action
2025-08-07 13:58:04 -07:00
Guro
dee63efcf4 feat: add ttyd and cloudflared tunnel integration
Add support for exposing Claude's terminal interface via browser using ttyd and cloudflared tunnel.

- Add cloudflare_tunnel_token input parameter to both action.yml files
- Spawn ttyd process on port 7681 to serve Claude's CLI interface
- Start cloudflared tunnel process with provided token to expose via web
- Implement proper process cleanup in finally block
- Add 3-second startup delay for process initialization

When cloudflare_tunnel_token is provided, users can access Claude's interactive terminal through their browser via the cloudflared tunnel.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-07 12:53:44 -07:00
Aner Cohen
7afc848186 fix: improve GitHub suggestion guidelines in review mode to prevent code duplication (#422)
* fix: prevent duplicate function signatures in review mode suggestions

This fixes a critical bug in the experimental review mode where GitHub
suggestions could create duplicate function signatures when applied.

The issue occurred because:
- GitHub suggestions REPLACE the entire selected line range
- Claude wasn't aware of this behavior and would include the function
  signature in multi-line suggestions, causing duplication

Changes:
- Added detailed instructions about GitHub's line replacement behavior
- Provided clear examples for single-line vs multi-line suggestions
- Added explicit warnings about common mistakes (duplicate signatures)
- Improved code readability by using a codeBlock variable instead of
  escaped backticks in template strings

This ensures Claude creates syntactically correct suggestions that
won't break code when applied through GitHub's suggestion feature.

* chore: format
2025-08-07 08:56:30 -07:00
Graham Campbell
6debac392b Go with Opus 4.1 (#420) 2025-08-06 21:22:15 -07:00
GitHub Actions
55fb6a96d0 chore: bump Claude Code version to 1.0.70 2025-08-06 19:59:40 +00:00
8 changed files with 130 additions and 25 deletions

View File

@@ -9,10 +9,21 @@ on:
types: [opened, assigned]
pull_request_review:
types: [submitted]
workflow_dispatch:
inputs:
cloudflare_tunnel_token:
description: 'Cloudflare tunnel token to expose Claude UI via browser'
required: false
type: string
direct_prompt:
description: 'Direct instruction for Claude'
required: false
type: string
jobs:
claude:
if: |
github.event_name == 'workflow_dispatch' ||
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
@@ -36,4 +47,7 @@ jobs:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
allowed_tools: "Bash(bun install),Bash(bun test:*),Bash(bun run format),Bash(bun typecheck)"
custom_instructions: "You have also been granted tools for editing files and running bun commands (install, run, test, typecheck) for testing your changes: bun install, bun test, bun run format, bun typecheck."
model: "claude-opus-4-20250514"
model: "claude-opus-4-1-20250805"
cloudflare_tunnel_token: ${{ github.event.inputs.cloudflare_tunnel_token }}
direct_prompt: ${{ github.event.inputs.direct_prompt }}
mode: ${{ github.event_name == 'workflow_dispatch' && 'agent' || 'tag' }}

View File

@@ -114,6 +114,10 @@ inputs:
description: "Restrict network access to these domains only (newline-separated). If not set, no restrictions are applied. Provider domains are auto-detected."
required: false
default: ""
cloudflare_tunnel_token:
description: "Cloudflare tunnel token to expose Claude UI via browser (optional)"
required: false
default: ""
outputs:
execution_file:
@@ -172,7 +176,7 @@ runs:
echo "Base-action dependencies installed"
cd -
# Install Claude Code globally
bun install -g @anthropic-ai/claude-code@1.0.69
bun install -g @anthropic-ai/claude-code@1.0.70
- name: Setup Network Restrictions
if: steps.prepare.outputs.contains_trigger == 'true' && inputs.experimental_allowed_domains != ''
@@ -206,6 +210,7 @@ runs:
INPUT_CLAUDE_ENV: ${{ inputs.claude_env }}
INPUT_FALLBACK_MODEL: ${{ inputs.fallback_model }}
INPUT_EXPERIMENTAL_SLASH_COMMANDS_DIR: ${{ github.action_path }}/slash-commands
INPUT_CLOUDFLARE_TUNNEL_TOKEN: ${{ inputs.cloudflare_tunnel_token }}
# Model configuration
ANTHROPIC_MODEL: ${{ inputs.model || inputs.anthropic_model }}

View File

@@ -69,7 +69,7 @@ Add the following to your workflow file:
uses: anthropics/claude-code-base-action@beta
with:
prompt: "Review and fix TypeScript errors"
model: "claude-opus-4-20250514"
model: "claude-opus-4-1-20250805"
fallback_model: "claude-sonnet-4-20250514"
allowed_tools: "Bash(git:*),View,GlobTool,GrepTool,BatchTool"
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
@@ -217,7 +217,7 @@ Provide the settings configuration directly as a JSON string:
prompt: "Your prompt here"
settings: |
{
"model": "claude-opus-4-20250514",
"model": "claude-opus-4-1-20250805",
"env": {
"DEBUG": "true",
"API_URL": "https://api.example.com"

View File

@@ -87,6 +87,10 @@ inputs:
description: "Whether to use Node.js dependency caching (set to true only for Node.js projects with lock files)"
required: false
default: "false"
cloudflare_tunnel_token:
description: "Cloudflare tunnel token to expose Claude UI via browser (optional)"
required: false
default: ""
outputs:
conclusion:
@@ -118,7 +122,7 @@ runs:
- name: Install Claude Code
shell: bash
run: bun install -g @anthropic-ai/claude-code@1.0.69
run: bun install -g @anthropic-ai/claude-code@1.0.70
- name: Run Claude Code Action
shell: bash
@@ -147,6 +151,7 @@ runs:
INPUT_CLAUDE_ENV: ${{ inputs.claude_env }}
INPUT_FALLBACK_MODEL: ${{ inputs.fallback_model }}
INPUT_EXPERIMENTAL_SLASH_COMMANDS_DIR: ${{ inputs.experimental_slash_commands_dir }}
INPUT_CLOUDFLARE_TUNNEL_TOKEN: ${{ inputs.cloudflare_tunnel_token }}
# Provider configuration
ANTHROPIC_API_KEY: ${{ inputs.anthropic_api_key }}

View File

@@ -5,6 +5,7 @@ import { preparePrompt } from "./prepare-prompt";
import { runClaude } from "./run-claude";
import { setupClaudeCodeSettings } from "./setup-claude-code-settings";
import { validateEnvironmentVariables } from "./validate-env";
import { spawn } from "child_process";
async function run() {
try {
@@ -21,7 +22,40 @@ async function run() {
promptFile: process.env.INPUT_PROMPT_FILE || "",
});
await runClaude(promptConfig.path, {
// Setup ttyd and cloudflared tunnel if token provided
let ttydProcess: any = null;
let cloudflaredProcess: any = null;
if (process.env.INPUT_CLOUDFLARE_TUNNEL_TOKEN) {
console.log("Setting up ttyd and cloudflared tunnel...");
// Start ttyd process in background
ttydProcess = spawn("ttyd", ["-p", "7681", "-i", "0.0.0.0", "claude"], {
stdio: "inherit",
detached: true,
});
ttydProcess.on("error", (error: Error) => {
console.warn(`ttyd process error: ${error.message}`);
});
// Start cloudflared tunnel
cloudflaredProcess = spawn("cloudflared", ["tunnel", "run", "--token", process.env.INPUT_CLOUDFLARE_TUNNEL_TOKEN], {
stdio: "inherit",
detached: true,
});
cloudflaredProcess.on("error", (error: Error) => {
console.warn(`cloudflared process error: ${error.message}`);
});
// Give processes time to start up
await new Promise(resolve => setTimeout(resolve, 3000));
console.log("ttyd and cloudflared tunnel started");
}
try {
await runClaude(promptConfig.path, {
allowedTools: process.env.INPUT_ALLOWED_TOOLS,
disallowedTools: process.env.INPUT_DISALLOWED_TOOLS,
maxTurns: process.env.INPUT_MAX_TURNS,
@@ -32,6 +66,23 @@ async function run() {
fallbackModel: process.env.INPUT_FALLBACK_MODEL,
model: process.env.ANTHROPIC_MODEL,
});
} finally {
// Clean up processes
if (ttydProcess) {
try {
ttydProcess.kill("SIGTERM");
} catch (e) {
console.warn("Failed to terminate ttyd process");
}
}
if (cloudflaredProcess) {
try {
cloudflaredProcess.kill("SIGTERM");
} catch (e) {
console.warn("Failed to terminate cloudflared process");
}
}
}
} catch (error) {
core.setFailed(`Action failed with error: ${error}`);
core.setOutput("conclusion", "failure");

View File

@@ -134,7 +134,7 @@ describe("setupClaudeCodeSettings", () => {
// Then, add new settings
const newSettings = JSON.stringify({
newKey: "newValue",
model: "claude-opus-4-20250514",
model: "claude-opus-4-1-20250805",
});
await setupClaudeCodeSettings(newSettings, testHomeDir);
@@ -145,7 +145,7 @@ describe("setupClaudeCodeSettings", () => {
expect(settings.enableAllProjectMcpServers).toBe(true);
expect(settings.existingKey).toBe("existingValue");
expect(settings.newKey).toBe("newValue");
expect(settings.model).toBe("claude-opus-4-20250514");
expect(settings.model).toBe("claude-opus-4-1-20250805");
});
test("should copy slash commands to .claude directory when path provided", async () => {

View File

@@ -252,7 +252,7 @@ You can provide Claude Code settings to customize behavior such as model selecti
with:
settings: |
{
"model": "claude-opus-4-20250514",
"model": "claude-opus-4-1-20250805",
"env": {
"DEBUG": "true",
"API_URL": "https://api.example.com"

View File

@@ -103,6 +103,9 @@ export const reviewMode: Mode = {
? formatBody(contextData.body, imageUrlMap)
: "No description provided";
// Using a variable for code blocks to avoid escaping backticks in the template string
const codeBlock = "```";
return `You are Claude, an AI assistant specialized in code reviews for GitHub pull requests. You are operating in REVIEW MODE, which means you should focus on providing thorough code review feedback using GitHub MCP tools for inline comments and suggestions.
<formatted_context>
@@ -155,17 +158,46 @@ REVIEW MODE WORKFLOW:
- This provides the full context and latest state of the code
- Look at the changed_files section above to see which files were modified
2. Add comments:
- use Bash(gh issue comment:*) to add top-level comments
- Use mcp__github_inline_comment__create_inline_comment to add inline comments (prefer this where possible)
- Parameters:
* path: The file path (e.g., "src/index.js")
* line: Line number for single-line comments
* startLine & line: For multi-line comments (startLine is the first line, line is the last)
* side: "LEFT" (old code) or "RIGHT" (new code)
* subjectType: "line" for line-level comments
* body: Your comment text
2. Create review comments using GitHub MCP tools:
- Use Bash(gh issue comment:*) for general PR-level comments
- Use mcp__github_inline_comment__create_inline_comment for line-specific feedback (strongly preferred)
3. When creating inline comments with suggestions:
CRITICAL: GitHub's suggestion blocks REPLACE the ENTIRE line range you select
- For single-line comments: Use 'line' parameter only
- For multi-line comments: Use both 'startLine' and 'line' parameters
- The 'body' parameter should contain your comment and/or suggestion block
How to write code suggestions correctly:
a) To remove a line (e.g., removing console.log on line 22):
- Set line: 22
- Body: ${codeBlock}suggestion
${codeBlock}
(Empty suggestion block removes the line)
b) To modify a single line (e.g., fixing line 22):
- Set line: 22
- Body: ${codeBlock}suggestion
await this.emailInput.fill(email);
${codeBlock}
c) To replace multiple lines (e.g., lines 21-23):
- Set startLine: 21, line: 23
- Body must include ALL lines being replaced:
${codeBlock}suggestion
async typeEmail(email: string): Promise<void> {
await this.emailInput.fill(email);
}
${codeBlock}
COMMON MISTAKE TO AVOID:
Never duplicate code in suggestions. For example, DON'T do this:
${codeBlock}suggestion
async typeEmail(email: string): Promise<void> {
async typeEmail(email: string): Promise<void> { // WRONG: Duplicate signature!
await this.emailInput.fill(email);
}
${codeBlock}
REVIEW GUIDELINES:
@@ -179,13 +211,11 @@ REVIEW GUIDELINES:
- Provide:
* Specific, actionable feedback
* Code suggestions when possible (following GitHub's format exactly)
* Clear explanations of issues
* Constructive criticism
* Code suggestions using the exact format described above
* Clear explanations of issues found
* Constructive criticism with solutions
* Recognition of good practices
* For complex changes that require multiple modifications:
- Create separate comments for each logical change
- Or explain the full solution in text without a suggestion block
* For complex changes: Create separate inline comments for each logical change
- Communication:
* All feedback goes through GitHub's review system