From 62efcef50847bc81972d8d42bfb530986eaf1152 Mon Sep 17 00:00:00 2001 From: kingboung Date: Mon, 11 May 2026 20:52:18 +0800 Subject: [PATCH] refactor: consolidate review skill registration and fix command conflicts - Merge strict:review/strict:security-review into reviewSkills.ts (single file registers all four commands: /review, /security-review, /strict:review, /strict:security-review) - Remove conflicting prompt commands from src/commands/ (review.ts, security-review.ts) so bundled skills take precedence - Remove REVIEW_AGENTS import from builtInAgents.ts and mcp.ts - Remove agent generation logic from generate-review-builtin.ts - Configure allowedTools and model: 'inherit' per claudecode spec - Switch test branch to optimize/agent-prompts Co-Authored-By: Claude Opus 4.7 --- scripts/generate-review-builtin.ts | 25 +-------- src/commands.ts | 3 +- src/commands/review.ts | 19 ++----- src/commands/security-review.ts | 17 ------ src/costrict/skills/reviewSkills.ts | 83 +++++++++++++++-------------- src/entrypoints/mcp.ts | 3 +- 6 files changed, 50 insertions(+), 100 deletions(-) delete mode 100644 src/commands/security-review.ts diff --git a/scripts/generate-review-builtin.ts b/scripts/generate-review-builtin.ts index 2fe830ac0..7515a99a5 100644 --- a/scripts/generate-review-builtin.ts +++ b/scripts/generate-review-builtin.ts @@ -22,14 +22,13 @@ const __dirname = path.dirname(__filename) const bundledReviewDir = path.resolve(__dirname, '../packages/builtin-tools/bundled-review') const builtinSkillsFile = path.resolve(__dirname, '../src/costrict/review/skill/builtin.ts') -const builtinAgentsFile = path.resolve(__dirname, '../src/costrict/review/agent/builtin.ts') type IndexJson = { skills: Array<{ name: string; path: Record }> } const REPO = 'zgsm-ai/costrict-review' -const BRANCH = 'main' +const BRANCH = 'optimize/agent-prompts' const CLONE_URL = `git@github.com:${REPO}.git` function git(...args: string[]): { ok: boolean; stdout: string; stderr: string } { @@ -266,27 +265,6 @@ export function getSkillMetadata(skillName: string, locale: string): { name: str console.log(`\nāœ“ Generated ${builtinSkillsFile}`) } -async function generateBuiltinAgents(_commitSha: string): Promise { - const content = `// This file is auto-generated by scripts/generate-review-builtin.ts -// Do not edit manually -// Agents have been migrated to skills in costrict-review - -import type { BuiltInAgentDefinition } from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js' - -export const REVIEW_AGENTS: BuiltInAgentDefinition[] = [] - -export const AGENT_VERSIONS: Record = {} - -export const PRIMARY_REVIEW_AGENT = '' - -export const SUB_REVIEW_AGENT = '' -` - - await mkdir(path.dirname(builtinAgentsFile), { recursive: true }) - await fs.writeFile(builtinAgentsFile, content, 'utf-8') - console.log(`āœ“ Generated ${builtinAgentsFile}`) -} - async function generateBuiltinReview() { console.log('\nšŸš€ CSC — Downloading Builtin Review Skills\n') @@ -335,7 +313,6 @@ async function generateBuiltinReview() { console.log(`āœ“ Bundled review directory: ${bundledReviewDir}`) await generateBuiltinSkills(commitSha) - await generateBuiltinAgents(commitSha) console.log('\nšŸ’” Run `bun run build` to compile\n') } diff --git a/src/commands.ts b/src/commands.ts index 15746227e..3ddf3e80b 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -38,7 +38,7 @@ import pr_comments from './commands/pr_comments/index.js' import releaseNotes from './commands/release-notes/index.js' import rename from './commands/rename/index.js' import resume from './commands/resume/index.js' -import review, { ultrareview } from './commands/review.js' +import { ultrareview } from './commands/review.js' import session from './commands/session/index.js' import share from './commands/share/index.js' import skills from './commands/skills/index.js' @@ -351,7 +351,6 @@ const COMMANDS = memoize((): Command[] => [ favorite, theme, feedback, - review, ultrareview, rewind, terminalSetup, diff --git a/src/commands/review.ts b/src/commands/review.ts index 2fcab7b52..7da35f436 100644 --- a/src/commands/review.ts +++ b/src/commands/review.ts @@ -1,23 +1,13 @@ -import type { ContentBlockParam } from '@anthropic-ai/sdk/resources/messages.js' -import type { Command } from '../commands.js' -import type { ToolUseContext } from '../Tool.js' import { isUltrareviewEnabled } from './review/ultrareviewEnabled.js' +import type { Command } from '../commands.js' // Legal wants the explicit surface name plus a docs link visible before the // user triggers, so the description carries "Claude Code on the web" + URL. const CCR_TERMS_URL = 'https://costrict.ai/docs/en/claude-code-on-the-web' -const review: Command = { - type: 'prompt', - name: 'review', - description: 'Review code for defects, security vulnerabilities, memory issues, and logic errors', - progressMessage: 'reviewing code', - contentLength: 0, - source: 'builtin', - async getPromptForCommand(args, _context): Promise { - return [{ type: 'text', text: args }] - }, -} +// /review is registered as a bundled skill via registerReviewSkills() in +// src/costrict/skills/reviewSkills.ts, which provides the full SKILL.md +// content and reference files. This file only provides /ultrareview. // /ultrareview is the ONLY entry point to the remote bughunter path — // /review stays purely local. local-jsx type renders the overage permission @@ -30,5 +20,4 @@ const ultrareview: Command = { load: () => import('./review/ultrareviewCommand.js'), } -export default review export { ultrareview } diff --git a/src/commands/security-review.ts b/src/commands/security-review.ts deleted file mode 100644 index 7e48c187b..000000000 --- a/src/commands/security-review.ts +++ /dev/null @@ -1,17 +0,0 @@ -import type { ContentBlockParam } from '@anthropic-ai/sdk/resources/messages.js' -import type { Command } from '../commands.js' -import type { ToolUseContext } from '../Tool.js' - -const securityReview: Command = { - type: 'prompt', - name: 'security-review', - description: 'Complete a security review of the pending changes on the current branch', - progressMessage: 'analyzing code changes for security risks', - contentLength: 0, - source: 'builtin', - async getPromptForCommand(args, _context): Promise { - return [{ type: 'text', text: args }] - }, -} - -export default securityReview diff --git a/src/costrict/skills/reviewSkills.ts b/src/costrict/skills/reviewSkills.ts index 57c1f914a..84ae3ce03 100644 --- a/src/costrict/skills/reviewSkills.ts +++ b/src/costrict/skills/reviewSkills.ts @@ -7,51 +7,54 @@ import { const LOCALE_MAP: Record = { zh: 'zh-CN', en: 'en' } -export function registerReviewSkills(): void { +function getLocale(): string { const lang = getResolvedLanguage() - const locale = LOCALE_MAP[lang] ?? 'zh-CN' + return LOCALE_MAP[lang] ?? 'zh-CN' +} +function registerSkillVariant( + name: string, + skillKey: string, + files: Record, + description: string, +): void { + registerBundledSkill({ + name, + description, + whenToUse: description, + userInvocable: true, + disableModelInvocation: true, + allowedTools: [ + 'Glob', + 'Grep', + 'Read', + 'TodoWrite', + 'Bash', + 'Agent', + ], + model: 'inherit', + context: 'fork', + files, + async getPromptForCommand(args) { + return [{ type: 'text', text: args.trim() || `Please perform a ${skillKey}.` }] + }, + }) +} + +export function registerReviewSkills(): void { + const locale = getLocale() const localeFiles = SKILL_FILES[locale] const localeMetadata = SKILL_METADATA[locale] - if (!localeFiles) return + if (!localeFiles || !localeMetadata) return - for (const [skillName, files] of Object.entries(localeFiles)) { - const meta = localeMetadata?.[skillName] - if (!meta) continue + for (const [skillKey, files] of Object.entries(localeFiles)) { + const meta = localeMetadata[skillKey] + if (!meta || !files) continue - registerBundledSkill({ - name: meta.name, - description: meta.description, - whenToUse: meta.description, - userInvocable: true, - disableModelInvocation: true, - allowedTools: [ - 'AskUserQuestion', - 'Read', - 'Glob', - 'Grep', - 'Bash', - 'Agent', - ], - context: 'fork', - files, - async getPromptForCommand(args) { - const userRequest = args.trim() - if (!userRequest) { - return [ - { - type: 'text', - text: `Please use the Skill tool to load '${meta.name}' skill.`, - }, - ] - } - return [ - { - type: 'text', - text: userRequest, - }, - ] - }, - }) + // Register /review, /security-review + registerSkillVariant(meta.name, skillKey, files, meta.description) + + // Register /strict:review, /strict:security-review + registerSkillVariant(`strict:${skillKey}`, skillKey, files, meta.description) } } diff --git a/src/entrypoints/mcp.ts b/src/entrypoints/mcp.ts index cbe36d5be..52e082933 100644 --- a/src/entrypoints/mcp.ts +++ b/src/entrypoints/mcp.ts @@ -8,7 +8,6 @@ import { type Tool, } from '@modelcontextprotocol/sdk/types.js' import { getDefaultAppState } from 'src/state/AppStateStore.js' -import review from '../commands/review.js' import type { Command } from '../commands.js' import { findToolByName, @@ -30,7 +29,7 @@ import { zodToJsonSchema } from '../utils/zodToJsonSchema.js' type ToolInput = Tool['inputSchema'] type ToolOutput = Tool['outputSchema'] -const MCP_COMMANDS: Command[] = [review] +const MCP_COMMANDS: Command[] = [] export async function startMCPServer( cwd: string,