fix: address PR review comments for v1.0 simplification

- Remove duplicate prompt field spread (line 160)
- Remove async from generatePrompt since slash commands are handled by Claude Code
- Add detailed comment explaining why prompt → agent mode logic
- Remove entire slash-commands loader and directories as Claude Code handles natively
- Simplify prompt generation to just pass through to Claude Code

These changes align with v1.0 philosophy: GitHub Action is a thin wrapper
that delegates everything to Claude Code for native handling.
This commit is contained in:
km-anthropic
2025-08-07 11:50:58 -07:00
parent acbef8d08c
commit 65896abe74
3 changed files with 10 additions and 169 deletions

View File

@@ -157,7 +157,6 @@ export function prepareContext(
disallowedTools: disallowedTools.join(","), disallowedTools: disallowedTools.join(","),
}), }),
...(prompt && { prompt }), ...(prompt && { prompt }),
...(prompt && { prompt }),
...(claudeBranch && { claudeBranch }), ...(claudeBranch && { claudeBranch }),
}; };
@@ -460,12 +459,12 @@ function getCommitInstructions(
} }
} }
export async function generatePrompt( export function generatePrompt(
context: PreparedContext, context: PreparedContext,
githubData: FetchDataResult, githubData: FetchDataResult,
useCommitSigning: boolean, useCommitSigning: boolean,
mode: Mode, mode: Mode,
): Promise<string> { ): string {
// v1.0: Simply pass through the prompt to Claude Code // v1.0: Simply pass through the prompt to Claude Code
// Claude Code handles slash commands natively // Claude Code handles slash commands natively
const prompt = context.prompt || ""; const prompt = context.prompt || "";
@@ -767,8 +766,8 @@ export async function createPrompt(
recursive: true, recursive: true,
}); });
// Generate the prompt directly (now async due to slash commands) // Generate the prompt directly
const promptContent = await generatePrompt( const promptContent = generatePrompt(
preparedContext, preparedContext,
githubData, githubData,
context.inputs.useCommitSigning, context.inputs.useCommitSigning,

View File

@@ -10,6 +10,12 @@ export type AutoDetectedMode = "tag" | "agent";
export function detectMode(context: GitHubContext): AutoDetectedMode { export function detectMode(context: GitHubContext): AutoDetectedMode {
// If prompt is provided, always use agent mode // If prompt is provided, always use agent mode
// Reasoning: When users provide explicit instructions via the prompt parameter,
// they want Claude to execute those instructions immediately without waiting for
// @claude mentions or other triggers. This aligns with the v1.0 philosophy where
// Claude Code handles everything - the GitHub Action is just a thin wrapper that
// passes through prompts directly to Claude Code for native handling (including
// slash commands). This provides the most direct and flexible interaction model.
if (context.inputs?.prompt) { if (context.inputs?.prompt) {
return "agent"; return "agent";
} }

View File

@@ -1,164 +0,0 @@
import { readFile, readdir, stat } from "fs/promises";
import { join, dirname } from "path";
import { fileURLToPath } from "url";
import * as yaml from "js-yaml";
export interface SlashCommandMetadata {
tools?: string[];
settings?: Record<string, any>;
description?: string;
}
export interface SlashCommand {
name: string;
metadata: SlashCommandMetadata;
content: string;
}
export interface ResolvedCommand {
expandedPrompt: string;
tools?: string[];
settings?: Record<string, any>;
}
const __dirname = dirname(fileURLToPath(import.meta.url));
const COMMANDS_DIR = join(__dirname, "../../slash-commands");
export async function resolveSlashCommand(
prompt: string,
variables?: Record<string, string | undefined>,
): Promise<ResolvedCommand> {
if (!prompt.startsWith("/")) {
return handleLegacyPrompts(prompt);
}
const parts = prompt.slice(1).split(" ");
const commandPath = parts[0];
const args = parts.slice(1);
if (!commandPath) {
return { expandedPrompt: prompt };
}
const commandParts = commandPath.split("/");
try {
const command = await loadCommand(commandParts);
if (!command) {
console.warn(`Slash command not found: ${commandPath}`);
return { expandedPrompt: prompt };
}
let expandedContent = command.content;
if (args.length > 0) {
expandedContent = expandedContent.replace(/\{args\}/g, args.join(" "));
}
if (variables) {
Object.entries(variables).forEach(([key, value]) => {
if (value !== undefined) {
const regex = new RegExp(`\\{${key}\\}`, "g");
expandedContent = expandedContent.replace(regex, value);
}
});
}
return {
expandedPrompt: expandedContent,
tools: command.metadata.tools,
settings: command.metadata.settings,
};
} catch (error) {
console.error(`Error loading slash command: ${error}`);
return { expandedPrompt: prompt };
}
}
async function loadCommand(
commandParts: string[],
): Promise<SlashCommand | null> {
const possiblePaths = [
join(COMMANDS_DIR, ...commandParts) + ".md",
join(COMMANDS_DIR, ...commandParts, "default.md"),
join(COMMANDS_DIR, commandParts[0] + ".md"),
];
for (const filePath of possiblePaths) {
try {
const fileContent = await readFile(filePath, "utf-8");
return parseCommandFile(commandParts.join("/"), fileContent);
} catch (error) {
continue;
}
}
return null;
}
function parseCommandFile(name: string, content: string): SlashCommand {
let metadata: SlashCommandMetadata = {};
let commandContent = content;
const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
if (frontmatterMatch && frontmatterMatch[1]) {
try {
const parsedYaml = yaml.load(frontmatterMatch[1]);
if (parsedYaml && typeof parsedYaml === "object") {
metadata = parsedYaml as SlashCommandMetadata;
}
commandContent = frontmatterMatch[2]?.trim() || content;
} catch (error) {
console.warn(`Failed to parse frontmatter for command ${name}:`, error);
}
}
return {
name,
metadata,
content: commandContent,
};
}
export async function listAvailableCommands(): Promise<string[]> {
const commands: string[] = [];
async function scanDirectory(dir: string, prefix = ""): Promise<void> {
try {
const entries = await readdir(dir);
for (const entry of entries) {
const fullPath = join(dir, entry);
const entryStat = await stat(fullPath);
if (entryStat.isDirectory()) {
await scanDirectory(fullPath, prefix ? `${prefix}/${entry}` : entry);
} else if (entry.endsWith(".md")) {
const commandName = entry.replace(".md", "");
if (commandName !== "default") {
commands.push(prefix ? `${prefix}/${commandName}` : commandName);
} else if (prefix) {
commands.push(prefix);
}
}
}
} catch (error) {
console.error(`Error scanning directory ${dir}:`, error);
}
}
await scanDirectory(COMMANDS_DIR);
return commands.sort();
}
function handleLegacyPrompts(prompt: string): ResolvedCommand {
const legacyKeys = ["override_prompt", "direct_prompt"];
for (const key of legacyKeys) {
const envValue = process.env[key.toUpperCase()];
if (envValue) {
console.log(`Using legacy ${key} as prompt`);
return { expandedPrompt: envValue };
}
}
return { expandedPrompt: prompt };
}