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 <noreply@anthropic.com>
This commit is contained in:
kingboung 2026-05-11 20:52:18 +08:00
parent a5235ab03c
commit 62efcef508
6 changed files with 50 additions and 100 deletions

View File

@ -22,14 +22,13 @@ const __dirname = path.dirname(__filename)
const bundledReviewDir = path.resolve(__dirname, '../packages/builtin-tools/bundled-review') const bundledReviewDir = path.resolve(__dirname, '../packages/builtin-tools/bundled-review')
const builtinSkillsFile = path.resolve(__dirname, '../src/costrict/review/skill/builtin.ts') const builtinSkillsFile = path.resolve(__dirname, '../src/costrict/review/skill/builtin.ts')
const builtinAgentsFile = path.resolve(__dirname, '../src/costrict/review/agent/builtin.ts')
type IndexJson = { type IndexJson = {
skills: Array<{ name: string; path: Record<string, string> }> skills: Array<{ name: string; path: Record<string, string> }>
} }
const REPO = 'zgsm-ai/costrict-review' const REPO = 'zgsm-ai/costrict-review'
const BRANCH = 'main' const BRANCH = 'optimize/agent-prompts'
const CLONE_URL = `git@github.com:${REPO}.git` const CLONE_URL = `git@github.com:${REPO}.git`
function git(...args: string[]): { ok: boolean; stdout: string; stderr: string } { 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}`) console.log(`\n✓ Generated ${builtinSkillsFile}`)
} }
async function generateBuiltinAgents(_commitSha: string): Promise<void> {
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<string, string> = {}
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() { async function generateBuiltinReview() {
console.log('\n🚀 CSC — Downloading Builtin Review Skills\n') console.log('\n🚀 CSC — Downloading Builtin Review Skills\n')
@ -335,7 +313,6 @@ async function generateBuiltinReview() {
console.log(`✓ Bundled review directory: ${bundledReviewDir}`) console.log(`✓ Bundled review directory: ${bundledReviewDir}`)
await generateBuiltinSkills(commitSha) await generateBuiltinSkills(commitSha)
await generateBuiltinAgents(commitSha)
console.log('\n💡 Run `bun run build` to compile\n') console.log('\n💡 Run `bun run build` to compile\n')
} }

View File

@ -38,7 +38,7 @@ import pr_comments from './commands/pr_comments/index.js'
import releaseNotes from './commands/release-notes/index.js' import releaseNotes from './commands/release-notes/index.js'
import rename from './commands/rename/index.js' import rename from './commands/rename/index.js'
import resume from './commands/resume/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 session from './commands/session/index.js'
import share from './commands/share/index.js' import share from './commands/share/index.js'
import skills from './commands/skills/index.js' import skills from './commands/skills/index.js'
@ -351,7 +351,6 @@ const COMMANDS = memoize((): Command[] => [
favorite, favorite,
theme, theme,
feedback, feedback,
review,
ultrareview, ultrareview,
rewind, rewind,
terminalSetup, terminalSetup,

View File

@ -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 { isUltrareviewEnabled } from './review/ultrareviewEnabled.js'
import type { Command } from '../commands.js'
// Legal wants the explicit surface name plus a docs link visible before the // 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. // 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 CCR_TERMS_URL = 'https://costrict.ai/docs/en/claude-code-on-the-web'
const review: Command = { // /review is registered as a bundled skill via registerReviewSkills() in
type: 'prompt', // src/costrict/skills/reviewSkills.ts, which provides the full SKILL.md
name: 'review', // content and reference files. This file only provides /ultrareview.
description: 'Review code for defects, security vulnerabilities, memory issues, and logic errors',
progressMessage: 'reviewing code',
contentLength: 0,
source: 'builtin',
async getPromptForCommand(args, _context): Promise<ContentBlockParam[]> {
return [{ type: 'text', text: args }]
},
}
// /ultrareview is the ONLY entry point to the remote bughunter path — // /ultrareview is the ONLY entry point to the remote bughunter path —
// /review stays purely local. local-jsx type renders the overage permission // /review stays purely local. local-jsx type renders the overage permission
@ -30,5 +20,4 @@ const ultrareview: Command = {
load: () => import('./review/ultrareviewCommand.js'), load: () => import('./review/ultrareviewCommand.js'),
} }
export default review
export { ultrareview } export { ultrareview }

View File

@ -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<ContentBlockParam[]> {
return [{ type: 'text', text: args }]
},
}
export default securityReview

View File

@ -7,51 +7,54 @@ import {
const LOCALE_MAP: Record<string, string> = { zh: 'zh-CN', en: 'en' } const LOCALE_MAP: Record<string, string> = { zh: 'zh-CN', en: 'en' }
export function registerReviewSkills(): void { function getLocale(): string {
const lang = getResolvedLanguage() const lang = getResolvedLanguage()
const locale = LOCALE_MAP[lang] ?? 'zh-CN' return LOCALE_MAP[lang] ?? 'zh-CN'
}
function registerSkillVariant(
name: string,
skillKey: string,
files: Record<string, string>,
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 localeFiles = SKILL_FILES[locale]
const localeMetadata = SKILL_METADATA[locale] const localeMetadata = SKILL_METADATA[locale]
if (!localeFiles) return if (!localeFiles || !localeMetadata) return
for (const [skillName, files] of Object.entries(localeFiles)) { for (const [skillKey, files] of Object.entries(localeFiles)) {
const meta = localeMetadata?.[skillName] const meta = localeMetadata[skillKey]
if (!meta) continue if (!meta || !files) continue
registerBundledSkill({ // Register /review, /security-review
name: meta.name, registerSkillVariant(meta.name, skillKey, files, meta.description)
description: meta.description,
whenToUse: meta.description, // Register /strict:review, /strict:security-review
userInvocable: true, registerSkillVariant(`strict:${skillKey}`, skillKey, files, meta.description)
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,
},
]
},
})
} }
} }

View File

@ -8,7 +8,6 @@ import {
type Tool, type Tool,
} from '@modelcontextprotocol/sdk/types.js' } from '@modelcontextprotocol/sdk/types.js'
import { getDefaultAppState } from 'src/state/AppStateStore.js' import { getDefaultAppState } from 'src/state/AppStateStore.js'
import review from '../commands/review.js'
import type { Command } from '../commands.js' import type { Command } from '../commands.js'
import { import {
findToolByName, findToolByName,
@ -30,7 +29,7 @@ import { zodToJsonSchema } from '../utils/zodToJsonSchema.js'
type ToolInput = Tool['inputSchema'] type ToolInput = Tool['inputSchema']
type ToolOutput = Tool['outputSchema'] type ToolOutput = Tool['outputSchema']
const MCP_COMMANDS: Command[] = [review] const MCP_COMMANDS: Command[] = []
export async function startMCPServer( export async function startMCPServer(
cwd: string, cwd: string,