mirror of
https://github.com/anthropics/claude-code-action.git
synced 2026-01-24 07:24:12 +08:00
Compare commits
2 Commits
demo/subtl
...
feat/ttyd-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7680c1d501 | ||
|
|
dee63efcf4 |
14
.github/workflows/claude.yml
vendored
14
.github/workflows/claude.yml
vendored
@@ -9,10 +9,21 @@ on:
|
|||||||
types: [opened, assigned]
|
types: [opened, assigned]
|
||||||
pull_request_review:
|
pull_request_review:
|
||||||
types: [submitted]
|
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:
|
jobs:
|
||||||
claude:
|
claude:
|
||||||
if: |
|
if: |
|
||||||
|
github.event_name == 'workflow_dispatch' ||
|
||||||
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
|
(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_comment' && contains(github.event.comment.body, '@claude')) ||
|
||||||
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
|
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
|
||||||
@@ -37,3 +48,6 @@ jobs:
|
|||||||
allowed_tools: "Bash(bun install),Bash(bun test:*),Bash(bun run format),Bash(bun typecheck)"
|
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."
|
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-1-20250805"
|
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' }}
|
||||||
|
|||||||
@@ -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."
|
description: "Restrict network access to these domains only (newline-separated). If not set, no restrictions are applied. Provider domains are auto-detected."
|
||||||
required: false
|
required: false
|
||||||
default: ""
|
default: ""
|
||||||
|
cloudflare_tunnel_token:
|
||||||
|
description: "Cloudflare tunnel token to expose Claude UI via browser (optional)"
|
||||||
|
required: false
|
||||||
|
default: ""
|
||||||
|
|
||||||
outputs:
|
outputs:
|
||||||
execution_file:
|
execution_file:
|
||||||
@@ -206,6 +210,7 @@ runs:
|
|||||||
INPUT_CLAUDE_ENV: ${{ inputs.claude_env }}
|
INPUT_CLAUDE_ENV: ${{ inputs.claude_env }}
|
||||||
INPUT_FALLBACK_MODEL: ${{ inputs.fallback_model }}
|
INPUT_FALLBACK_MODEL: ${{ inputs.fallback_model }}
|
||||||
INPUT_EXPERIMENTAL_SLASH_COMMANDS_DIR: ${{ github.action_path }}/slash-commands
|
INPUT_EXPERIMENTAL_SLASH_COMMANDS_DIR: ${{ github.action_path }}/slash-commands
|
||||||
|
INPUT_CLOUDFLARE_TUNNEL_TOKEN: ${{ inputs.cloudflare_tunnel_token }}
|
||||||
|
|
||||||
# Model configuration
|
# Model configuration
|
||||||
ANTHROPIC_MODEL: ${{ inputs.model || inputs.anthropic_model }}
|
ANTHROPIC_MODEL: ${{ inputs.model || inputs.anthropic_model }}
|
||||||
|
|||||||
@@ -87,6 +87,10 @@ inputs:
|
|||||||
description: "Whether to use Node.js dependency caching (set to true only for Node.js projects with lock files)"
|
description: "Whether to use Node.js dependency caching (set to true only for Node.js projects with lock files)"
|
||||||
required: false
|
required: false
|
||||||
default: "false"
|
default: "false"
|
||||||
|
cloudflare_tunnel_token:
|
||||||
|
description: "Cloudflare tunnel token to expose Claude UI via browser (optional)"
|
||||||
|
required: false
|
||||||
|
default: ""
|
||||||
|
|
||||||
outputs:
|
outputs:
|
||||||
conclusion:
|
conclusion:
|
||||||
@@ -147,6 +151,7 @@ runs:
|
|||||||
INPUT_CLAUDE_ENV: ${{ inputs.claude_env }}
|
INPUT_CLAUDE_ENV: ${{ inputs.claude_env }}
|
||||||
INPUT_FALLBACK_MODEL: ${{ inputs.fallback_model }}
|
INPUT_FALLBACK_MODEL: ${{ inputs.fallback_model }}
|
||||||
INPUT_EXPERIMENTAL_SLASH_COMMANDS_DIR: ${{ inputs.experimental_slash_commands_dir }}
|
INPUT_EXPERIMENTAL_SLASH_COMMANDS_DIR: ${{ inputs.experimental_slash_commands_dir }}
|
||||||
|
INPUT_CLOUDFLARE_TUNNEL_TOKEN: ${{ inputs.cloudflare_tunnel_token }}
|
||||||
|
|
||||||
# Provider configuration
|
# Provider configuration
|
||||||
ANTHROPIC_API_KEY: ${{ inputs.anthropic_api_key }}
|
ANTHROPIC_API_KEY: ${{ inputs.anthropic_api_key }}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { preparePrompt } from "./prepare-prompt";
|
|||||||
import { runClaude } from "./run-claude";
|
import { runClaude } from "./run-claude";
|
||||||
import { setupClaudeCodeSettings } from "./setup-claude-code-settings";
|
import { setupClaudeCodeSettings } from "./setup-claude-code-settings";
|
||||||
import { validateEnvironmentVariables } from "./validate-env";
|
import { validateEnvironmentVariables } from "./validate-env";
|
||||||
|
import { spawn } from "child_process";
|
||||||
|
|
||||||
async function run() {
|
async function run() {
|
||||||
try {
|
try {
|
||||||
@@ -21,6 +22,39 @@ async function run() {
|
|||||||
promptFile: process.env.INPUT_PROMPT_FILE || "",
|
promptFile: process.env.INPUT_PROMPT_FILE || "",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 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, {
|
await runClaude(promptConfig.path, {
|
||||||
allowedTools: process.env.INPUT_ALLOWED_TOOLS,
|
allowedTools: process.env.INPUT_ALLOWED_TOOLS,
|
||||||
disallowedTools: process.env.INPUT_DISALLOWED_TOOLS,
|
disallowedTools: process.env.INPUT_DISALLOWED_TOOLS,
|
||||||
@@ -32,6 +66,23 @@ async function run() {
|
|||||||
fallbackModel: process.env.INPUT_FALLBACK_MODEL,
|
fallbackModel: process.env.INPUT_FALLBACK_MODEL,
|
||||||
model: process.env.ANTHROPIC_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) {
|
} catch (error) {
|
||||||
core.setFailed(`Action failed with error: ${error}`);
|
core.setFailed(`Action failed with error: ${error}`);
|
||||||
core.setOutput("conclusion", "failure");
|
core.setOutput("conclusion", "failure");
|
||||||
|
|||||||
Reference in New Issue
Block a user