feat: register /review and /security-review via registerBundledSkill

Replace indirect Skill-tool-based routing with direct bundled skill
registration using SKILL_FILES, matching /strict:review approach.

- reviewSkills.ts registers all four commands (review, security-review,
  strict:review, strict:security-review) with embedded files
- Remove review command from commands.ts (now bundled skill)
- Simplify review.ts to only export ultrareview
- Update mcp.ts to get review command from bundled skills

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
kingboung 2026-05-12 16:52:43 +08:00
parent d96f74a3fc
commit 7425b59826
5 changed files with 17 additions and 28 deletions

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,27 +1,13 @@
import type { ContentBlockParam } from '@anthropic-ai/sdk/resources/messages.js'
import type { Command } from '../commands.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 { CommandLocale } from 'src/costrict/command/locales/index.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'
// /review is registered as a bundled skill via extract-to-disk mechanism, // /review is registered as a bundled skill via registerReviewSkills() in
// discovered by the standard skill scanner. Here we provide a prompt-based // src/costrict/skills/reviewSkills.ts, which provides the full SKILL.md
// command that routes to the Skill tool for non-skill contexts (e.g. MCP). // content and reference files. This file only provides /ultrareview.
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<ContentBlockParam[]> {
return [{ type: 'text', text: CommandLocale.get('review').replace('$ARGUMENTS', 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
@ -34,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

@ -23,11 +23,12 @@ const ALLOWED_TOOLS = [
'Agent', 'Agent',
] ]
function registerStrictReviewSkill( function registerReviewSkill(
name: string, name: string,
skillKey: string, skillKey: string,
files: Record<string, string>, files: Record<string, string>,
description: string, description: string,
forked: boolean,
): void { ): void {
registerBundledSkill({ registerBundledSkill({
name, name,
@ -36,7 +37,7 @@ function registerStrictReviewSkill(
userInvocable: true, userInvocable: true,
disableModelInvocation: true, disableModelInvocation: true,
allowedTools: ALLOWED_TOOLS, allowedTools: ALLOWED_TOOLS,
context: 'fork', context: forked ? 'fork' : undefined,
files, files,
async getPromptForCommand(args) { async getPromptForCommand(args) {
const template = CommandLocale.get(skillKey) const template = CommandLocale.get(skillKey)
@ -48,7 +49,7 @@ function registerStrictReviewSkill(
}) })
} }
export function registerStrictReviewSkills(): void { export function registerReviewSkills(): void {
const locale = getLocale() const locale = getLocale()
const localeFiles = SKILL_FILES[locale] const localeFiles = SKILL_FILES[locale]
const localeMetadata = SKILL_METADATA[locale] const localeMetadata = SKILL_METADATA[locale]
@ -58,6 +59,10 @@ export function registerStrictReviewSkills(): void {
const meta = localeMetadata[skillKey] const meta = localeMetadata[skillKey]
if (!meta || !files) continue if (!meta || !files) continue
registerStrictReviewSkill(`strict:${skillKey}`, skillKey, files, meta.description) // /review, /security-review — inline in main session
registerReviewSkill(meta.name, skillKey, files, meta.description, false)
// /strict:review, /strict:security-review — forked sub-agent
registerReviewSkill(`strict:${skillKey}`, skillKey, files, meta.description, true)
} }
} }

View File

@ -8,7 +8,7 @@ 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 { getBundledSkills } from 'src/skills/bundledSkills.js'
import type { Command } from '../commands.js' import type { Command } from '../commands.js'
import { import {
findToolByName, findToolByName,
@ -30,7 +30,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[] = getBundledSkills().filter(c => c.name === 'review')
export async function startMCPServer( export async function startMCPServer(
cwd: string, cwd: string,

View File

@ -17,7 +17,7 @@ import { registerUpdateConfigSkill } from './updateConfig.js'
import { registerVerifySkill } from './verify.js' import { registerVerifySkill } from './verify.js'
import { registerStrictPlanSkill } from 'src/costrict/skills/strictPlan.js' import { registerStrictPlanSkill } from 'src/costrict/skills/strictPlan.js'
import { registerStrictSpecSkill } from 'src/costrict/skills/strictSpec.js' import { registerStrictSpecSkill } from 'src/costrict/skills/strictSpec.js'
import { registerStrictReviewSkills } from 'src/costrict/skills/strictReview.js' import { registerReviewSkills } from 'src/costrict/skills/reviewSkills.js'
import { registerProjectWikiSkill } from 'src/costrict/skills/projectWiki.js' import { registerProjectWikiSkill } from 'src/costrict/skills/projectWiki.js'
import { registerTddSkill } from 'src/costrict/skills/tdd.js' import { registerTddSkill } from 'src/costrict/skills/tdd.js'
@ -39,7 +39,7 @@ export function initBundledSkills(): void {
registerTddSkill() registerTddSkill()
registerStrictPlanSkill() registerStrictPlanSkill()
registerStrictSpecSkill() registerStrictSpecSkill()
registerStrictReviewSkills() registerReviewSkills()
registerKeybindingsSkill() registerKeybindingsSkill()
registerVerifySkill() registerVerifySkill()
registerDebugSkill() registerDebugSkill()