一键导入
code-audit
Comprehensive static code analysis to enforce architectural patterns, conventions, and code quality standards.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Comprehensive static code analysis to enforce architectural patterns, conventions, and code quality standards.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
| name | code-audit |
| description | Comprehensive static code analysis to enforce architectural patterns, conventions, and code quality standards. |
Enforce code quality and consistency standards across the entire codebase through automated checks.
What it checks (19 checks, each with its own script):
What it doesn't check:
arch-audit skillThis template uses a core/domain separation:
Both follow the same patterns and rules. New features you create will be domain features.
All checks:
node ./.claude/skills/code-audit/scripts/run_all_checks.mjs
Generate report:
node ./.claude/skills/code-audit/scripts/generate_report.mjs
Individual checks:
node ./.claude/skills/code-audit/scripts/check_imports.mjs
node ./.claude/skills/code-audit/scripts/check_exports.mjs
node ./.claude/skills/code-audit/scripts/check_redux_abstraction.mjs
node ./.claude/skills/code-audit/scripts/check_service_imports.mjs
node ./.claude/skills/code-audit/scripts/check_i18n_coverage.mjs
node ./.claude/skills/code-audit/scripts/check_any_usage.mjs
node ./.claude/skills/code-audit/scripts/check_suppressions.mjs
node ./.claude/skills/code-audit/scripts/check_god_files.mjs
node ./.claude/skills/code-audit/scripts/check_todos.mjs
node ./.claude/skills/code-audit/scripts/check_logs.mjs
node ./.claude/skills/code-audit/scripts/check_saga_patterns.mjs
node ./.claude/skills/code-audit/scripts/check_type_assertions.mjs
node ./.claude/skills/code-audit/scripts/check_reexports.mjs
node ./.claude/skills/code-audit/scripts/check_type_imports.mjs
node ./.claude/skills/code-audit/scripts/check_dangerous_html.mjs
node ./.claude/skills/code-audit/scripts/check_react_keys.mjs
node ./.claude/skills/code-audit/scripts/check_magic_numbers.mjs
node ./.claude/skills/code-audit/scripts/check_strict_mode.mjs
node ./.claude/skills/code-audit/scripts/check_dep_arrays.mjs
RULE: Use absolute path aliases (@/features/*, @/services/*, etc.) instead of relative imports when crossing directory boundaries.
Why: Makes imports clear, prevents broken paths when moving files, enables IDE navigation.
Allowed:
./slice.ts, ../models/session/actions.tsViolations:
import { useAuth } from '../../features/oauth/hooks/useAuth'import { api } from '../services/api'Fix:
import { useAuth } from '@/core/features/oauth/hooks/useAuth'import { api } from '@/services/api'RULE: Use named exports only. No default exports, no index.ts barrel files.
Why: Makes refactoring safer, imports explicit, no ambiguity.
Violations:
export default function MyComponent() { ... }index.ts files that re-export from other filesFix:
export const MyComponent: React.FC = () => { ... }Exceptions:
*.stories.tsx) - require default exports*.d.ts) - may use defaultRULE: Components NEVER import useDispatch, useSelector, or RootState directly. They use feature hooks.
Why: Abstracts Redux implementation, components don't know about state management.
Pattern:
Components → Feature Hooks → Redux
(NEVER: Components → Redux directly)
Violations:
useDispatch from react-reduxRootStateuseSelectorFix:
useWalletActions(), useBlogActions()useWallet(), useAuth()useTypedSelector from @/hooks/useTypedSelector for cross-feature stateAllowed files (these ARE the abstraction layer):
(core|domain)/features/*/hooks/*.ts - can use useDispatch, useSelector, RootStatesrc/hooks/*.ts - can use useSelector, RootState(core|domain)/features/*/models/*/actionEffects/*.ts - can use RootStateRULE: Services (@/services/*) are ONLY imported in composition root (src/config/(core|domain)/*/services.ts).
Why: Dependency injection pattern - features receive services through interfaces, easy to swap implementations.
Violations:
@/services/ethersV6/wallet/WalletAPI@/services/oauth/OAuthServiceFix:
IFeatureApi interfacesrc/config/(core|domain)/{feature}/services.tsAllowed files:
src/config/services.ts (root composition, if exists)src/config/(core|domain)/*/services.ts (feature-specific composition)RULE: All user-facing text must be wrapped in t() function for translation.
Why: Enables multi-language support, i18next tooling extracts text.
Violations:
<Button>Click me</Button>const message = "Error occurred"Fix:
<Button>{t('Click me')}</Button>const message = t('Error occurred')Excluded (not user-facing):
log.debug('...'), console.log('...')className, id, href, srcException paths (developer tools, not user UI):
core/features/slice-manager/components/SliceDebugPanelcore/features/i18n/components/LangMenu/LangModaldomain/layout/ErrorFallbackRULE: Never use any type. Use proper types, generics, or unknown.
Why: Defeats TypeScript's type safety, allows runtime errors.
Violations:
function process(data: any) { ... }const items: any[] = [...]Fix:
<T> for reusable codeunknown for truly dynamic types (forces type guards)Exceptions:
*.d.ts) for external libraries*.test.ts) for mocking (prefer typed mocks)RULE: Never suppress errors with comments. Fix the underlying issue.
Why: Suppressions hide real bugs, accumulate technical debt.
Violations:
// @ts-ignore// @ts-nocheck// eslint-disable// prettier-ignoreFix: Address the root cause, don't hide it.
Exceptions:
@ts-expect-error (fails if error is fixed) with detailed commentRULE: Each file exports exactly ONE entity (interface, type, class, enum). File name matches entity name.
Why: Easy to find, clear purpose, follows Single Responsibility Principle.
Violations:
export interface declarationsexport type declarationsFix: Split into separate files.
Examples:
UserService.ts → export class UserServiceFeatureConfig.ts → export interface FeatureConfigConnectionState.ts → export type ConnectionStateExceptions:
*.test.ts, *.spec.ts)*.d.ts) for external libraries*.stories.tsx)Breadcrumb.tsx can have BreadcrumbProps)RULE: No technical debt markers in code. Track work in issue tracker instead.
Why: Markers indicate incomplete work, forgotten tasks, or known bugs.
Detected:
TODO, FIXME, HACK, XXX, BUGFix: Create GitHub issues, complete work, remove comments.
RULE: No console.* statements in production code. Use log.* from loglevel.
Why: Console statements can't be controlled in production, expose debug info.
Violations:
console.log(), console.error(), console.warn()Fix:
log.debug() - auto-disabled in productionlog.info(), log.warn(), log.error() - controlled log levelsRULE: Use single yield all([...]) for parallel operations. Multiple yield all in same function is inefficient.
Why: True parallelism requires combining effects into one yield all.
Violation:
yield all([effect1, effect2]);
yield all([effect3, effect4]); // Sequential, not parallel!
Fix:
yield all([effect1, effect2, effect3, effect4]); // Truly parallel
RULE: Never use as const or satisfies. Use proper types, interfaces, or enums instead.
Why: Type assertions are shortcuts that reduce code clarity, reusability, and maintainability. Proper type definitions are self-documenting and enforce better architecture.
Violations:
const colors = ["red", "blue"] as constconst config = { ... } satisfies Configconst options = { mode: "light" } as constFix:
type Color = "red" | "blue";
const colors: Color[] = ["red", "blue"];
const config: Config = { ... };
enum Mode {
Light = "light",
Dark = "dark"
}
const options = { mode: Mode.Light };
Why This Matters:
as const and satisfies are lazy shortcutsBetter alternatives:
interface for object shapestype for unions, intersections, and aliasesenum for constant sets of valuesconst with explicit type annotationsRULE: Never use re-export statements. Import directly from source files instead of re-exporting from intermediate files.
Why: Re-exports create indirection, make code harder to navigate, and obscure actual dependencies. Direct imports make the codebase more transparent and easier to refactor.
Violations:
export { Something } from './somewhere'export * from './somewhere'export * as namespace from './somewhere'export type { TypeName } from './somewhere'index.ts with re-exportsFix:
// Instead of re-exporting in index.ts
// ❌ export { UserService } from './UserService';
// Import directly from source
// ✅ import { UserService } from './path/to/UserService';
Why This Matters:
The Rule:
RULE: Never use the type keyword in import statements. TypeScript automatically removes type-only imports during compilation.
Why: The type keyword is redundant visual noise. TypeScript's compiler can automatically detect and remove type-only imports without the keyword, making code cleaner and simpler.
Violations:
import type { User } from './types'import { type User } from './types'import { Data, type User } from './types' (mixed)Fix:
import { User, Data } from './types';
Why This Matters:
type keyword adds visual clutter without benefitThe Rule:
import type { X }import { type X }import { X }RULE: Never use dangerouslySetInnerHTML - it bypasses React's XSS protection.
Why: Opens XSS vulnerabilities, allows arbitrary HTML injection, user-controlled content can execute malicious scripts.
Violations:
<div dangerouslySetInnerHTML={{ __html: userContent }} />Fix:
<div>{content}</div>
import DOMPurify from 'dompurify';
<div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(content) }} />
Why This Matters:
The Rule:
RULE: Always use stable, unique identifiers as keys in lists. Never use array index or omit keys.
Why: Using array index as key causes bugs when list order changes. Missing keys cause React warnings and unpredictable re-renders.
Violations:
items.map((item, index) => <Item key={index} />)
items.map(item => <Item {...item} />)
Fix:
items.map(item => <Item key={item.id} {...item} />)
Why This Matters:
The Rule:
key prop when rendering lists with .map()item.id)RULE: Never use magic numbers - use named constants instead.
Why: Magic numbers make code harder to understand, difficult to maintain and update, no semantic meaning without context.
Focus: Time-related values (setTimeout, setInterval, delays)
Violations:
setTimeout(callback, 3600000); // What is 3600000?
await delay(5000); // 5000 what?
Fix:
const ONE_HOUR_MS = 3600000;
setTimeout(callback, ONE_HOUR_MS);
const FIVE_SECONDS_MS = 5000;
await delay(FIVE_SECONDS_MS);
Why This Matters:
Detection Focus:
The Rule:
{VALUE}_{UNIT}_MS (e.g., ONE_HOUR_MS, 30_SECONDS_MS)setTimeout(fn, 0))RULE: TypeScript's strict mode must be enabled in tsconfig.json.
Why: Enables 8+ critical type safety checks, catches errors at compile time, industry best practice.
Violation:
tsconfig.json missing "strict": true"strict": false in compilerOptionsFix:
{
"compilerOptions": {
"strict": true
}
}
What Strict Mode Includes:
Why This Matters:
The Rule:
"strict": true in tsconfig.jsonRULE: Dependency arrays must be correct - no missing reactive values, no stable values, no side effects in memoization hooks.
Why: Incorrect dependency arrays cause stale closures, unnecessary re-renders, memory leaks, and bugs that are hard to debug.
Empty [] but reactive values are used inside - will cause stale closures.
Violations:
i18n.resolvedLanguage with empty array:
useEffect(() => {
actions.fetchPosts({ language: i18n.resolvedLanguage });
}, []); // i18n.resolvedLanguage is used but not in deps!
Fix:
useEffect(() => {
actions.fetchPosts({ language: i18n.resolvedLanguage });
}, [i18n.resolvedLanguage]); // Will re-run when language changes
Reactive Patterns Detected:
i18n.resolvedLanguage, i18n.language (language changes)props.* (prop access)Note: t function is stable and should NOT be in deps. If you need to react to language changes, use i18n.resolvedLanguage.
These values are guaranteed stable by React/libraries and should NOT be in dependency arrays.
Violations:
useEffect(() => {
navigate('/home');
}, [isAuthenticated, navigate]); // navigate is stable!
Fix:
useEffect(() => {
navigate('/home');
}, [isAuthenticated]); // Only reactive values
Known Stable Values:
useState setters: setX, setState, etc.useReducer dispatchuseNavigate() from react-router: navigateuseTranslation() from i18next: tdispatchactions (from useActions())pageLink, homeRoute, pageRoutesRefThese hooks must be PURE - no side effects allowed.
Violations:
const data = useMemo(() => {
fetch('/api/data'); // WRONG! Side effect in useMemo
return processData();
}, [deps]);
const handler = useCallback(() => {
console.log('clicked'); // Side effect
doSomething();
}, []);
Fix:
// useMemo should be pure
const processed = useMemo(() => processData(rawData), [rawData]);
// Side effects go in useEffect
useEffect(() => {
fetch('/api/data').then(setData);
}, []);
Side Effects Detected:
fetch(), axios.* callsconsole.log/warn/error/infolocalStorage.*, sessionStorage.*document.*, window.location4+ dependencies may indicate over-specification or a need to refactor.
Warning:
useEffect(() => {
// Complex logic
}, [a, b, c, d, e]); // Too many deps - review
Fix:
useReducer for complex stateDirect API calls in useEffect miss caching, deduplication, and proper error handling.
Info:
useEffect(() => {
fetch('/api/users').then(setUsers); // Direct fetch
}, []);
Consider:
Note: actions.fetchX() via Redux Saga is OK - it triggers saga, not direct API call.
Why Avoid Direct Fetch:
Each check reports:
Reports are saved to reports/{date}/code-audit-report.md when using generate_report.mjs.
src/ directoryArchitecture dependency analysis to ensure proper feature isolation and composition root pattern.
Comprehensive documentation generation through automated codebase analysis, pattern detection, and diagram creation.
Dependency health analysis to detect outdated packages and unused dependencies.
Safe minor dependency updates with validation (lint/test/build) and automatic rollback on failure.
Security vulnerability analysis to detect hardcoded secrets, dangerous patterns, and unsafe code practices.
Test coverage analysis to ensure adequate testing, Storybook coverage, and test quality.