用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/trycompai/comp --skill forms命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
Run all audit checks (RBAC, hooks, design system, tests) and verify build
Check code for the most common, high-risk security vulnerabilities (broken access control, tenant isolation, injection, secrets, SSRF, auth/session, unsafe file handling, mass assignment) before it ships. Use after editing any API controller, guard, or auth code (apps/api/src/auth/**), a Prisma schema/query, a file-upload/webhook handler, or before committing/pushing security-sensitive changes.
How to reuse ANY integration check's results in a feature via the universal CheckResultsService (apps/api integration-platform). Use whenever a feature needs data produced by an integration check — "show 2FA status on People", "surface AWS S3 findings in X", "reuse a check's results", "per-user/per-resource results from a connected integration", "which integrations feed task T". Read this BEFORE writing your own IntegrationCheckResult / CheckRunRepository query — don't hand-roll it.
基于 SOC 职业分类
正在显示 SKILL.md
| name | forms |
| description | Use when building forms - covers React Hook Form, Zod validation, and form patterns |
Source Cursor rule: .cursor/rules/forms.mdc.
Original Cursor alwaysApply: false.
All forms MUST use React Hook Form with Zod validation.
import { zodResolver } from '@hookform/resolvers/zod';
import { useForm } from 'react-hook-form';
import { z } from 'zod';
import { Button, Input } from '@trycompai/design-system';
// 1. Define schema
const formSchema = z.object({
email: z.string().email('Invalid email'),
password: z.string().min(8, 'Min 8 characters'),
});
// 2. Infer type
type FormData = z.infer<typeof formSchema>;
// 3. Use in component
function MyForm() {
const {
register,
handleSubmit,
formState: { errors, isSubmitting },
} = useForm<FormData>({
resolver: zodResolver(formSchema),
});
return (
<form onSubmit={handleSubmit(onSubmit)}>
<Input {...register('email')} />
{errors.email && <p>{errors.email.message}</p>}
<Button type="submit" loading={isSubmitting}>
Submit
</Button>
</form>
);
}
const profileSchema = z.object({
// Strings
name: z.string().min(1, 'Required'),
email: z.string().email(),
website: z.string().url().optional(),
// Numbers (coerce for inputs)
age: z.coerce.number().int().min(0),
price: z.coerce.number().positive(),
// Arrays
tags: z.array(z.string()).min(1),
// Enums
status: z.enum(['active', 'inactive']),
});
// Cross-field validation
const passwordSchema = z.object({
password: z.string().min(8),
confirmPassword: z.string(),
}).refine(d => d.password === d.confirmPassword, {
message: ,
: [],
});
import { Controller } from 'react-hook-form';
import { Select, SelectContent, SelectItem, SelectTrigger } from '@trycompai/design-system';
<Controller
name="status"
control={control}
render={({ field }) => (
<Select onValueChange={field.onChange} value={field.value}>
<SelectTrigger>{field.value || 'Select...'}</SelectTrigger>
<SelectContent>
<SelectItem value="active">Active</SelectItem>
<SelectItem value="inactive">Inactive</SelectItem>
</SelectContent>
</Select>
)}
/>
const {
register,
handleSubmit,
control,
watch, // Watch field values
setValue, // Set field programmatically
reset, // Reset form
setError, // Set error manually
formState: {
errors, // Field errors
isSubmitting, // Submitting
isValid, // All valid
isDirty, // Modified
},
} = useForm<FormData>({
resolver: zodResolver(schema),
mode: 'onChange', // Validate on change
});
const onSubmit = async (data: FormData) => {
try {
await submitToApi(data);
} catch (error) {
// Field-specific error
setError('email', { message: 'Email taken' });
// Or root error
setError('root', { message: 'Something went wrong' });
}
};
// Display root error
{errors.root && <p>{errors.root.message}</p>}
import { useFieldArray } from 'react-hook-form';
const { fields, append, remove } = useFieldArray({
control,
name: 'items',
});
{fields.map((field, index) => (
<div key={field.id}>
<Input {...register(`items.${index}.name`)} />
<Button type="button" onClick={() => remove(index)}>Remove</Button>
</div>
))}
<Button type="button" onClick={() => append({ name: '' })}>Add</Button>
// ❌ useState for form fields
const [email, setEmail] = useState('');
// ❌ Manual validation
if (email.length < 5) setError('Too short');
// ❌ Missing button type (defaults to submit)
<Button onClick={handleCancel}>Cancel</Button>
// ✅ Correct
const { register } = useForm();
const schema = z.object({ email: z.string().min(5) });
<Button type="button" onClick={handleCancel}>Cancel</Button>