From d9e73dc5d40f7f45de11227399a6cdbbaa2fef84 Mon Sep 17 00:00:00 2001 From: Hidetake Iwata Date: Fri, 13 Jun 2025 09:03:58 +0900 Subject: [PATCH] Accept multiline input for allowed_tools and disallowed_tools --- README.md | 11 +++++-- src/github/context.ts | 18 ++++++------ test/github/context.test.ts | 57 +++++++++++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 10 deletions(-) create mode 100644 test/github/context.test.ts diff --git a/README.md b/README.md index 89d92a7..dddbe6f 100644 --- a/README.md +++ b/README.md @@ -347,8 +347,15 @@ Claude does **not** have access to execute arbitrary Bash commands by default. I ```yaml - uses: anthropics/claude-code-action@beta with: - allowed_tools: "Bash(npm install),Bash(npm run test),Edit,Replace,NotebookEditCell" - disallowed_tools: "TaskOutput,KillTask" + allowed_tools: | + Bash(npm install) + Bash(npm run test) + Edit + Replace + NotebookEditCell + disallowed_tools: | + TaskOutput + KillTask # ... other inputs ``` diff --git a/src/github/context.ts b/src/github/context.ts index 1e19303..d8b1581 100644 --- a/src/github/context.ts +++ b/src/github/context.ts @@ -52,14 +52,8 @@ export function parseGitHubContext(): ParsedGitHubContext { inputs: { triggerPhrase: process.env.TRIGGER_PHRASE ?? "@claude", assigneeTrigger: process.env.ASSIGNEE_TRIGGER ?? "", - allowedTools: (process.env.ALLOWED_TOOLS ?? "") - .split(",") - .map((tool) => tool.trim()) - .filter((tool) => tool.length > 0), - disallowedTools: (process.env.DISALLOWED_TOOLS ?? "") - .split(",") - .map((tool) => tool.trim()) - .filter((tool) => tool.length > 0), + allowedTools: parseMultilineInput(process.env.ALLOWED_TOOLS ?? ""), + disallowedTools: parseMultilineInput(process.env.DISALLOWED_TOOLS ?? ""), customInstructions: process.env.CUSTOM_INSTRUCTIONS ?? "", directPrompt: process.env.DIRECT_PROMPT ?? "", baseBranch: process.env.BASE_BRANCH, @@ -116,6 +110,14 @@ export function parseGitHubContext(): ParsedGitHubContext { } } +export function parseMultilineInput(s: string): string[] { + return s + .split(/,|[\n\r]+/) + .map((tool) => tool.replace(/#.+$/, "")) + .map((tool) => tool.trim()) + .filter((tool) => tool.length > 0); +} + export function isIssuesEvent( context: ParsedGitHubContext, ): context is ParsedGitHubContext & { payload: IssuesEvent } { diff --git a/test/github/context.test.ts b/test/github/context.test.ts new file mode 100644 index 0000000..bfdf026 --- /dev/null +++ b/test/github/context.test.ts @@ -0,0 +1,57 @@ +import { describe, it, expect } from "bun:test"; +import { parseMultilineInput } from "../../src/github/context"; + +describe("parseMultilineInput", () => { + it("should parse a comma-separated string", () => { + const input = `Bash(bun install),Bash(bun test:*),Bash(bun typecheck)`; + const result = parseMultilineInput(input); + expect(result).toEqual([ + "Bash(bun install)", + "Bash(bun test:*)", + "Bash(bun typecheck)", + ]); + }); + + it("should parse multiline string", () => { + const input = `Bash(bun install) +Bash(bun test:*) +Bash(bun typecheck)`; + const result = parseMultilineInput(input); + expect(result).toEqual([ + "Bash(bun install)", + "Bash(bun test:*)", + "Bash(bun typecheck)", + ]); + }); + + it("should parse comma-separated multiline line", () => { + const input = `Bash(bun install),Bash(bun test:*) +Bash(bun typecheck)`; + const result = parseMultilineInput(input); + expect(result).toEqual([ + "Bash(bun install)", + "Bash(bun test:*)", + "Bash(bun typecheck)", + ]); + }); + + it("should ignore comments", () => { + const input = `Bash(bun install), +Bash(bun test:*) # For testing +# For type checking +Bash(bun typecheck) +`; + const result = parseMultilineInput(input); + expect(result).toEqual([ + "Bash(bun install)", + "Bash(bun test:*)", + "Bash(bun typecheck)", + ]); + }); + + it("should parse an empty string", () => { + const input = ""; + const result = parseMultilineInput(input); + expect(result).toEqual([]); + }); +});