@devflow-tools/plugin-react 0.3.2 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -394,63 +394,188 @@ export const reactPlugin = {
394
394
  {
395
395
  name: "new-feature",
396
396
  description: "新功能开发流程:需求分析 → 代码 → 测试 → Review",
397
- version: "1.0.0",
397
+ version: "2.0.0",
398
398
  steps: [
399
399
  {
400
400
  id: "analyze-requirements",
401
- description: "分析需求并拆解为可执行任务",
402
- type: "llm",
403
- timeout: 15000,
401
+ title: "分析需求",
402
+ instruction: [
403
+ "## 分析需求",
404
+ "",
405
+ "理解用户描述的功能需求,将其拆解为可执行的任务清单。",
406
+ "",
407
+ "**执行动作**:",
408
+ "1. 理解用户描述的功能需求,提取核心目标和边界条件",
409
+ "2. 将需求拆解为 3-5 个可执行的子任务,每个子任务对应一个独立的代码变更",
410
+ "3. 识别技术约束(依赖版本、浏览器兼容性、性能要求)",
411
+ "4. 确认数据流向:该功能需要哪些 API、状态管理、路由配置",
412
+ "5. 使用 Read 工具读取项目的 `package.json` 和 `tsconfig.json` 确认技术栈版本",
413
+ "",
414
+ "**产出格式**:",
415
+ "```",
416
+ "feature_summary: <一句话描述>",
417
+ "subtasks: [",
418
+ " { id: 1, description: '...', files_to_touch: ['...'] },",
419
+ " ...",
420
+ "]",
421
+ "constraints: ['...']",
422
+ "data_flow: <数据从 API/Store → 组件 → UI 的完整链路>",
423
+ "```",
424
+ ].join("\n"),
425
+ suggestedTools: ["Read", "Bash"],
426
+ output: "拆解后的任务清单、技术约束、数据流向",
404
427
  },
405
428
  {
406
429
  id: "impact-analysis",
407
- description: "评估变更影响范围(哪些文件/模块会被影响)",
408
- type: "llm",
430
+ title: "评估变更影响范围",
431
+ instruction: [
432
+ "## 评估变更影响范围",
433
+ "",
434
+ "基于 `analyze-requirements` 的任务清单,分析每个变更对现有代码的影响。",
435
+ "",
436
+ "**执行动作**:",
437
+ "1. 对每个待修改 / 新增的文件,查找所有依赖它的下游文件:",
438
+ " ```bash",
439
+ " grep -rn \"from.*<file_path>\" src/ --include='*.tsx' --include='*.ts' --include='*.jsx' --include='*.js'",
440
+ " ```",
441
+ "2. 检查是否修改了共享的类型定义、Context、Store:",
442
+ " ```bash",
443
+ " find src/ -type f \\( -name 'types.ts' -o -name 'store.ts' -o -name 'context.ts' \\) | head -20",
444
+ " ```",
445
+ "3. 评估路由变更影响:",
446
+ " ```bash",
447
+ " grep -rn \"Route\\|path:\" src/ --include='*.tsx' --include='*.ts' | head -30",
448
+ " ```",
449
+ "4. 标记高风险变更(影响 >5 个下游文件的变更)",
450
+ "5. 检查是否需要同步更新 Storybook、文档或 E2E 测试",
451
+ "",
452
+ "**产出格式**:",
453
+ "```",
454
+ "affected_files: [{ path, downstream_count, risk: 'high'|'medium'|'low' }]",
455
+ "shared_changes: [{ type: 'type'|'context'|'store', path, downstream_files: [...] }]",
456
+ "risk_summary: <高风险变更概述>",
457
+ "```",
458
+ ].join("\n"),
459
+ suggestedTools: ["Bash", "Read"],
460
+ output: "受影响文件清单、共享变更列表、风险评估",
409
461
  depends: ["analyze-requirements"],
410
- timeout: 15000,
411
462
  },
412
463
  {
413
464
  id: "check-existing-patterns",
414
- description: "检查项目中已有的类似实现模式",
415
- type: "simple",
465
+ title: "检查已有实现模式",
466
+ instruction: [
467
+ "## 检查项目中已有的类似实现模式",
468
+ "",
469
+ "避免重复造轮子,复用项目已有的组件、Hooks 和工具函数。",
470
+ "",
471
+ "**执行动作**:",
472
+ "1. 搜索项目中功能相似的现有组件:",
473
+ " ```bash",
474
+ " find src/components/ -type f -name '*.tsx' | head -50",
475
+ " ```",
476
+ "2. 查找已有的自定义 Hooks:",
477
+ " ```bash",
478
+ " find src/ -type f \\( -name 'use*.ts' -o -name 'use*.tsx' \\) | head -30",
479
+ " grep -rn '^export function use\\|^export const use' src/ --include='*.ts' --include='*.tsx'",
480
+ " ```",
481
+ "3. 查找已有的类型定义:",
482
+ " ```bash",
483
+ " find src/types/ -type f -name '*.ts' 2>/dev/null | head -20",
484
+ " grep -rn 'interface\\|type ' src/types/ --include='*.ts' 2>/dev/null | head -30",
485
+ " ```",
486
+ "4. 检查项目约定的文件组织方式和样式方案:",
487
+ " ```bash",
488
+ " ls -la src/",
489
+ " ls -la src/components/ 2>/dev/null",
490
+ " ```",
491
+ "5. 识别可复用的模式(组件结构、样式方案、测试模式)",
492
+ "",
493
+ "**产出格式**:",
494
+ "```",
495
+ "reusable_components: [{ name, path, description, reuse_approach: 'direct'|'extend'|'reference' }]",
496
+ "reusable_hooks: [{ name, path, description }]",
497
+ "existing_types: [{ name, path }]",
498
+ "project_patterns: { file_structure: '...', styling: '...', testing: '...' }",
499
+ "```",
500
+ ].join("\n"),
501
+ suggestedTools: ["Bash", "Read"],
502
+ output: "可复用的组件、Hooks、类型清单和项目模式",
416
503
  depends: ["analyze-requirements"],
417
- timeout: 10000,
418
504
  },
419
505
  {
420
506
  id: "implement",
421
- description: "按照项目约定生成组件/Hook/类型代码",
422
- type: "llm",
507
+ title: "实现功能代码",
508
+ instruction: [
509
+ "## 按照项目约定生成代码",
510
+ "",
511
+ "基于 `analyze-requirements`、`impact-analysis` 和 `check-existing-patterns` 的结果,实现功能代码。",
512
+ "",
513
+ "**执行动作**:",
514
+ "1. 按照项目文件结构约定创建新文件(参考 `check-existing-patterns` 发现的目录结构)",
515
+ "2. 优先复用已有的组件、Hooks 和工具函数",
516
+ "3. 遵循项目类型定义规范:",
517
+ " - Props 使用 `interface` 定义(不用 `type`)",
518
+ " - 事件处理器命名:`onXxx` 或 `handleXxx`",
519
+ "4. 确保所有新代码能通过 TypeScript 类型检查(无 `any`、无 `@ts-ignore`)",
520
+ "5. 使用 `React.memo` 包裹纯展示组件",
521
+ "6. 使用 `useMemo` / `useCallback` 避免不必要的重渲染(但不要过度优化)",
522
+ "7. 对关键逻辑添加注释",
523
+ "",
524
+ "**代码质量检查清单**:",
525
+ "- [ ] 所有函数组件(无 Class 组件)",
526
+ "- [ ] Props 有 TypeScript interface",
527
+ "- [ ] 无未使用的 import",
528
+ "- [ ] 无 `console.log` 残留",
529
+ "- [ ] 错误边界处理(try/catch 或 ErrorBoundary)",
530
+ "",
531
+ "**产出格式**:",
532
+ "```",
533
+ "files_created: [{ path, description }]",
534
+ "files_modified: [{ path, changes_summary }]",
535
+ "components: [{ name, path, is_memoized: true|false }]",
536
+ "hooks_used: ['useState', 'useEffect', ...]",
537
+ "```",
538
+ ].join("\n"),
539
+ suggestedTools: ["Read", "Edit", "Write"],
540
+ output: "创建和修改的文件清单、组件列表",
423
541
  depends: ["impact-analysis", "check-existing-patterns"],
424
- timeout: 30000,
425
- },
426
- {
427
- id: "type-check",
428
- description: "TypeScript 类型检查",
429
- type: "simple",
430
- depends: ["implement"],
431
- timeout: 15000,
432
542
  },
543
+ { id: "type-check", stepTemplate: "type-check", depends: ["implement"] },
433
544
  {
434
545
  id: "write-tests",
435
- description: "生成单元测试和集成测试",
436
- type: "llm",
546
+ title: "编写测试",
547
+ instruction: [
548
+ "## 生成单元测试和集成测试",
549
+ "",
550
+ "为新功能编写充分的测试用例。",
551
+ "",
552
+ "**执行动作**:",
553
+ "1. 找到项目的测试目录约定:",
554
+ " ```bash",
555
+ " find src/ -type d -name '__tests__' -o -name '*.test.*' | head -20",
556
+ " ```",
557
+ "2. 为每个新组件 / Hook 创建对应的测试文件",
558
+ "3. 测试覆盖:",
559
+ " - **渲染测试**:组件能正确渲染(含默认 Props 和边界 Props)",
560
+ " - **交互测试**:用户操作(点击、输入、提交)触发正确行为",
561
+ " - **异步测试**:API 调用、数据加载、loading / error 状态",
562
+ " - **Hook 测试**:使用 `renderHook` 测试自定义 Hooks",
563
+ "4. 使用 `describe` / `it` 组织测试,命名清晰",
564
+ "5. Mock 策略:API 调用使用 `vi.mock`,Context 使用 wrapper",
565
+ "",
566
+ "**产出格式**:",
567
+ "```",
568
+ "test_files_created: [{ path, test_count: N }]",
569
+ "coverage_target: { statements: '>80%', branches: '>75%' }",
570
+ "test_cases: [{ describe: '...', it: '...', status: 'written' }]",
571
+ "```",
572
+ ].join("\n"),
573
+ suggestedTools: ["Read", "Write", "Bash"],
574
+ output: "创建的测试文件清单、测试用例列表",
437
575
  depends: ["implement"],
438
- timeout: 20000,
439
- },
440
- {
441
- id: "run-tests",
442
- description: "运行全部测试确认通过",
443
- type: "simple",
444
- depends: ["type-check", "write-tests"],
445
- timeout: 60000,
446
- },
447
- {
448
- id: "code-review",
449
- description: "自动代码审查 + 人工确认",
450
- type: "manual",
451
- depends: ["run-tests"],
452
- timeout: 120000,
453
576
  },
577
+ { id: "run-tests", stepTemplate: "run-tests", depends: ["type-check", "write-tests"] },
578
+ { id: "code-review", stepTemplate: "human-review", depends: ["run-tests"] },
454
579
  ],
455
580
  triggers: [
456
581
  { type: "cli", command: "feature" },
@@ -461,59 +586,306 @@ export const reactPlugin = {
461
586
  {
462
587
  name: "performance-audit",
463
588
  description: "性能审计:渲染分析 → 优化方案 → 基准对比",
464
- version: "1.0.0",
589
+ version: "2.0.0",
465
590
  steps: [
466
591
  {
467
592
  id: "profile-renders",
468
- description: "使用 React DevTools Profiler 分析组件渲染次数和耗时",
469
- type: "simple",
470
- timeout: 20000,
593
+ title: "分析组件渲染性能",
594
+ instruction: [
595
+ "## 使用 React DevTools Profiler 分析组件渲染",
596
+ "",
597
+ "扫描项目源码,识别可能存在渲染性能问题的组件。",
598
+ "",
599
+ "**执行动作**:",
600
+ "1. 找出项目中所有 React 组件文件:",
601
+ " ```bash",
602
+ " find src/ -type f \\( -name '*.tsx' -o -name '*.jsx' \\) | head -100",
603
+ " ```",
604
+ "2. 检查每个组件的渲染复杂度:",
605
+ " - 组件 JSX 行数(>100 行的 JSX 为高风险)",
606
+ " - 嵌套层级(>3 层嵌套为高风险)",
607
+ " - 列表渲染(`.map` 调用次数)",
608
+ " ```bash",
609
+ " grep -rn '\\.map(' src/ --include='*.tsx' --include='*.jsx' | head -30",
610
+ " ```",
611
+ "3. 检查是否存在频繁渲染的嫌疑组件:",
612
+ " - 消费了全局 Context 的组件",
613
+ " - 使用了 `useState` / `useReducer` 且频繁更新的组件",
614
+ " ```bash",
615
+ " grep -rn 'useContext\\|useState\\|useReducer' src/ --include='*.tsx' --include='*.jsx' | wc -l",
616
+ " ```",
617
+ "4. 查看组件是否有 `React.memo` 包裹",
618
+ "",
619
+ "**产出格式**:",
620
+ "```",
621
+ "total_components: <N>",
622
+ "high_risk_components: [{ name, path, jsx_lines: N, map_calls: N, has_memo: false }]",
623
+ "context_consumers: [{ name, path, context_name: '...' }]",
624
+ "```",
625
+ ].join("\n"),
626
+ suggestedTools: ["Bash", "Read"],
627
+ output: "渲染性能风险分析、高风险组件清单",
471
628
  },
472
629
  {
473
630
  id: "audit-memoization",
474
- description: "检查 useMemo/useCallback/React.memo 使用情况",
475
- type: "simple",
476
- timeout: 15000,
631
+ title: "审查 Memoization 使用情况",
632
+ instruction: [
633
+ "## 检查 useMemo / useCallback / React.memo 使用情况",
634
+ "",
635
+ "**执行动作**:",
636
+ "1. 统计项目中 Memoization 的使用情况:",
637
+ " ```bash",
638
+ " echo '--- useMemo ---'",
639
+ " grep -rn 'useMemo' src/ --include='*.tsx' --include='*.ts' --include='*.jsx' | wc -l",
640
+ " echo '--- useCallback ---'",
641
+ " grep -rn 'useCallback' src/ --include='*.tsx' --include='*.ts' --include='*.jsx' | wc -l",
642
+ " echo '--- React.memo ---'",
643
+ " grep -rn 'React\\.memo\\|memo(' src/ --include='*.tsx' --include='*.jsx' | wc -l",
644
+ " ```",
645
+ "2. 检查缺失 memoization 的场景:",
646
+ " - 组件接收对象/数组/函数 props 但未被 `React.memo` 包裹",
647
+ " - 复杂计算(>5 行逻辑)未使用 `useMemo`",
648
+ " - 传递给子组件的回调函数未使用 `useCallback`",
649
+ "3. 检查过度 memoization 的场景:",
650
+ " - `useMemo` 包裹简单值(如常量、字面量)",
651
+ " - `useMemo` 的依赖数组每次渲染都变化",
652
+ " ```bash",
653
+ " grep -rn 'useMemo\\|useCallback' src/ --include='*.tsx' --include='*.ts' -A 3",
654
+ " ```",
655
+ "",
656
+ "**产出格式**:",
657
+ "```",
658
+ "memoization_stats: { useMemo: N, useCallback: N, React.memo: N }",
659
+ "missing_memoization: [{ file, line, issue: '函数 prop 未用 useCallback' }]",
660
+ "over_memoization: [{ file, line, issue: 'useMemo 包裹简单字面量' }]",
661
+ "```",
662
+ ].join("\n"),
663
+ suggestedTools: ["Bash", "Read"],
664
+ output: "Memoization 使用统计、缺失和过度使用的清单",
477
665
  },
478
666
  {
479
667
  id: "detect-rerenders",
480
- description: "检测不必要的重渲染(props 引用变化、context 更新)",
481
- type: "simple",
482
- timeout: 15000,
668
+ title: "检测不必要的重渲染",
669
+ instruction: [
670
+ "## 检测不必要的重渲染",
671
+ "",
672
+ "**执行动作**:",
673
+ "1. 检查 Props 引用稳定性问题:",
674
+ " ```bash",
675
+ " # 查找内联对象/数组/函数作为 props 传递",
676
+ " grep -rn '<[A-Z][a-zA-Z]* [^>]*style={{' src/ --include='*.tsx' --include='*.jsx'",
677
+ " grep -rn '<[A-Z][a-zA-Z]* [^>]*onClick={() =>' src/ --include='*.tsx' --include='*.jsx'",
678
+ " grep -rn '<[A-Z][a-zA-Z]* [^>]*\\[.*\\]' src/ --include='*.tsx' --include='*.jsx'",
679
+ " ```",
680
+ "2. 检查 Context 过度更新问题:",
681
+ " ```bash",
682
+ " # 查找 Context Provider 中包含频繁变化的值",
683
+ " grep -rn 'Provider' src/ --include='*.tsx' --include='*.ts' -B 2 -A 5",
684
+ " ```",
685
+ "3. 检查 key 使用问题:",
686
+ " ```bash",
687
+ " # 检查列表渲染中的 key 是否稳定",
688
+ " grep -rn 'key={' src/ --include='*.tsx' --include='*.jsx' | head -30",
689
+ " ```",
690
+ "4. 检查 useEffect 依赖数组不稳定(每次渲染都触发)",
691
+ "5. 检查 state 提升是否合理(是否应该拆分 state)",
692
+ "",
693
+ "**产出格式**:",
694
+ "```",
695
+ "inline_object_props: [{ file, line, component: '...' }]",
696
+ "inline_function_props: [{ file, line, component: '...' }]",
697
+ "context_rerender_risks: [{ context_name, provider_file, consumer_count: N }]",
698
+ "unstable_keys: [{ file, line, issue: '...' }]",
699
+ "```",
700
+ ].join("\n"),
701
+ suggestedTools: ["Bash", "Read"],
702
+ output: "不必要的重渲染原因清单",
483
703
  },
484
704
  {
485
705
  id: "analyze-bundle",
486
- description: "分析打包体积(大依赖、重复模块)",
487
- type: "simple",
488
- timeout: 20000,
706
+ title: "分析打包体积",
707
+ instruction: [
708
+ "## 分析打包体积",
709
+ "",
710
+ "**执行动作**:",
711
+ "1. 检查打包配置和产物:",
712
+ " ```bash",
713
+ " # 查看 package.json 的依赖大小",
714
+ " cat package.json | grep -A 50 '\"dependencies\"'",
715
+ " # 查看是否有 build 产物",
716
+ " ls -la dist/ 2>/dev/null || ls -la build/ 2>/dev/null || echo 'No build output found'",
717
+ " ```",
718
+ "2. 检查大依赖(常见的大包):",
719
+ " ```bash",
720
+ " # 检查 moment, lodash 全量导入等大依赖",
721
+ " grep -rn \"from 'moment'\\|from 'lodash'\\|from 'ramda'\" src/ --include='*.tsx' --include='*.ts'",
722
+ " # 检查是否有重复依赖",
723
+ " npm ls --depth=0 2>&1 | head -30",
724
+ " ```",
725
+ "3. 检查动态导入(懒加载)使用情况:",
726
+ " ```bash",
727
+ " grep -rn 'import(' src/ --include='*.tsx' --include='*.ts'",
728
+ " grep -rn 'React\\.lazy\\|lazy(' src/ --include='*.tsx' --include='*.ts'",
729
+ " ```",
730
+ "4. 检查 barrel file(index.ts)是否导致 tree-shaking 失效",
731
+ "5. 估算各依赖的体积占比",
732
+ "",
733
+ "**产出格式**:",
734
+ "```",
735
+ "large_dependencies: [{ name, estimated_size: 'N KB', reason: '全量导入 lodash' }]",
736
+ "lazy_loaded_components: [{ name, path }]",
737
+ "barrel_files: [{ path, exports_count: N, tree_shakeable: true|false }]",
738
+ "optimization_suggestions: ['...']",
739
+ "```",
740
+ ].join("\n"),
741
+ suggestedTools: ["Bash", "Read"],
742
+ output: "打包体积分析报告、大依赖清单、优化建议",
489
743
  },
490
744
  {
491
745
  id: "generate-report",
492
- description: "生成性能分析报告和优化优先级排序",
493
- type: "llm",
746
+ title: "生成性能分析报告",
747
+ instruction: [
748
+ "## 生成性能分析报告",
749
+ "",
750
+ "汇总所有分析结果,生成优先级排序的优化方案。",
751
+ "",
752
+ "**报告格式**:",
753
+ "```markdown",
754
+ "## React 性能审计报告",
755
+ "",
756
+ "### 概览",
757
+ "- 总组件数:<N>",
758
+ "- 高风险组件:<N>",
759
+ "- 缺失 memoization:<N> 处",
760
+ "- 不必要的重渲染:<N> 处",
761
+ "",
762
+ "### 优化建议(按优先级排序)",
763
+ "",
764
+ "#### P0 — 必须优化(影响用户感知性能)",
765
+ "| 问题 | 位置 | 预计收益 |",
766
+ "|------|------|----------|",
767
+ "",
768
+ "#### P1 — 建议优化(减少不必要计算)",
769
+ "| 问题 | 位置 | 预计收益 |",
770
+ "|------|------|----------|",
771
+ "",
772
+ "#### P2 — 可选优化(代码质量改善)",
773
+ "| 问题 | 位置 | 预计收益 |",
774
+ "|------|------|----------|",
775
+ "",
776
+ "### 打包优化",
777
+ "- 可替换的大依赖:[...]",
778
+ "- 可懒加载的组件:[...]",
779
+ "```",
780
+ ].join("\n"),
781
+ suggestedTools: ["Read"],
782
+ output: "分优先级的完整性能审计报告",
494
783
  depends: ["profile-renders", "audit-memoization", "detect-rerenders", "analyze-bundle"],
495
- timeout: 20000,
496
784
  },
497
785
  {
498
786
  id: "apply-optimizations",
499
- description: "应用优化(添加 memo、拆分组件、懒加载、虚拟列表)",
500
- type: "llm",
787
+ title: "应用性能优化",
788
+ instruction: [
789
+ "## 应用性能优化",
790
+ "",
791
+ "根据 `generate-report` 的优化建议,逐项应用代码变更。",
792
+ "",
793
+ "**执行动作**:",
794
+ "1. **P0 优化**(必须):",
795
+ " - 为大列表添加虚拟滚动(react-window / react-virtuoso)",
796
+ " - 为纯展示组件添加 `React.memo`",
797
+ " - 将内联对象/函数改为 `useMemo` / `useCallback`",
798
+ "2. **P1 优化**(建议):",
799
+ " - 拆分大型 Context(避免无关组件重渲染)",
800
+ " - 使用 `useDeferredValue` / `useTransition` 优化用户交互",
801
+ " - 组件懒加载:`React.lazy(() => import('./HeavyComponent'))`",
802
+ "3. **P2 优化**(可选):",
803
+ " - 替换大依赖(如 `moment` → `dayjs`、`lodash` → `lodash-es`)",
804
+ " - 优化 barrel file 以改善 tree-shaking",
805
+ "4. 每项优化后,使用 Edit 工具精准修改代码",
806
+ "5. 不做过度优化:简单组件不需要 memo",
807
+ "",
808
+ "**产出格式**:",
809
+ "```",
810
+ "optimizations_applied: [",
811
+ " { type: 'memo'|'useMemo'|'useCallback'|'lazy'|'virtual-list', file, changes_summary }",
812
+ "]",
813
+ "estimated_improvement: <预估渲染次数减少 / 体积减少>",
814
+ "```",
815
+ ].join("\n"),
816
+ suggestedTools: ["Read", "Edit", "Bash"],
817
+ output: "应用的优化清单、预估收益",
501
818
  depends: ["generate-report"],
502
- timeout: 30000,
503
819
  },
504
820
  {
505
821
  id: "benchmark-compare",
506
- description: "优化前后渲染次数和打包体积对比",
507
- type: "simple",
822
+ title: "优化前后对比",
823
+ instruction: [
824
+ "## 优化前后渲染次数和打包体积对比",
825
+ "",
826
+ "**执行动作**:",
827
+ "1. 重新检查优化后的代码状态:",
828
+ " ```bash",
829
+ " echo '--- 优化后 memoization ---'",
830
+ " grep -rn 'useMemo\\|useCallback\\|React\\.memo' src/ --include='*.tsx' --include='*.ts' | wc -l",
831
+ " echo '--- 优化后内联 props ---'",
832
+ " grep -rn '<[A-Z][a-zA-Z]* [^>]*style={{' src/ --include='*.tsx' --include='*.jsx'",
833
+ " ```",
834
+ "2. 运行构建查看产物大小变化:",
835
+ " ```bash",
836
+ " npm run build 2>&1 | tail -20",
837
+ " ```",
838
+ "3. 运行测试确认无回归:",
839
+ " ```bash",
840
+ " npm test 2>&1",
841
+ " ```",
842
+ "4. 对比优化前后指标",
843
+ "",
844
+ "**产出格式**:",
845
+ "```",
846
+ "before: { components: N, memoization_count: N, inline_props: N, bundle_size: 'N KB' }",
847
+ "after: { components: N, memoization_count: N, inline_props: N, bundle_size: 'N KB' }",
848
+ "delta: { memoization: +N, inline_props: -N, bundle_size: '-N KB' }",
849
+ "tests: passed | failed",
850
+ "```",
851
+ ].join("\n"),
852
+ suggestedTools: ["Bash", "Read"],
853
+ output: "优化前后指标对比",
508
854
  depends: ["apply-optimizations"],
509
- timeout: 30000,
510
855
  },
511
856
  {
512
857
  id: "approve-optimizations",
513
- description: "人工确认优化方案",
514
- type: "manual",
858
+ title: "人工确认优化方案",
859
+ instruction: [
860
+ "## 人工确认性能优化方案",
861
+ "",
862
+ "将所有优化结果和前后对比呈现给用户,等待确认。",
863
+ "",
864
+ "**呈现给用户的摘要**:",
865
+ "",
866
+ "### 📊 性能优化报告",
867
+ "",
868
+ "**优化项**:",
869
+ "- P0: <N> 项(必须优化)",
870
+ "- P1: <N> 项(建议优化)",
871
+ "- P2: <N> 项(可选优化)",
872
+ "",
873
+ "**指标变化**:",
874
+ "- 渲染性能:预计减少 <N> 次不必要的重渲染",
875
+ "- 打包体积:预计减少 <N> KB",
876
+ "",
877
+ "**修改文件**:<列出所有修改的文件>",
878
+ "",
879
+ "**等待用户操作**:",
880
+ "- 审查优化方案是否影响业务逻辑",
881
+ "- 确认后执行 `git commit`",
882
+ "",
883
+ "**注意**:此步骤必须等待用户明确确认后才能继续。",
884
+ ].join("\n"),
885
+ suggestedTools: ["Read"],
886
+ output: "用户确认结果",
515
887
  depends: ["benchmark-compare"],
516
- timeout: 60000,
888
+ requiresUserConfirmation: true,
517
889
  },
518
890
  ],
519
891
  triggers: [
@@ -525,65 +897,280 @@ export const reactPlugin = {
525
897
  {
526
898
  name: "hook-review",
527
899
  description: "Hooks 审查:规则检查 → 依赖分析 → 自动修复",
528
- version: "1.0.0",
900
+ version: "2.0.0",
529
901
  steps: [
530
902
  {
531
903
  id: "scan-all-hooks",
532
- description: "扫描项目中所有 Hooks 调用位置",
533
- type: "simple",
534
- timeout: 15000,
904
+ title: "全量扫描项目中所有 Hooks 调用位置",
905
+ instruction: [
906
+ "## 全量扫描所有 Hooks 调用位置",
907
+ "",
908
+ "必须遍历项目中**所有**源代码目录,不能只扫描部分目录。",
909
+ "",
910
+ "**第一步:发现所有源码目录**",
911
+ "```bash",
912
+ "# 找到所有包含 .tsx/.ts/.jsx/.js 文件的目录",
913
+ "find src/ -type f \\( -name '*.tsx' -o -name '*.ts' -o -name '*.jsx' -o -name '*.js' \\) | head -200",
914
+ "",
915
+ "# 特别列出所有 pages 子目录(如果有)",
916
+ "find src/pages/ -type d 2>/dev/null || echo 'No src/pages/ directory'",
917
+ "",
918
+ "# 列出所有 components 子目录",
919
+ "find src/components/ -type d 2>/dev/null || echo 'No src/components/ directory'",
920
+ "",
921
+ "# 列出所有 hooks 目录",
922
+ "find src/ -type d -name 'hooks' 2>/dev/null",
923
+ "```",
924
+ "",
925
+ "**第二步:全量 grep 所有 Hooks 调用**",
926
+ "```bash",
927
+ "# 搜索所有 React 内置 Hooks",
928
+ "grep -rn 'useState\\|useEffect\\|useMemo\\|useCallback\\|useRef\\|useContext\\|useReducer\\|useLayoutEffect\\|useImperativeHandle\\|useDebugValue\\|useTransition\\|useDeferredValue\\|useId' src/ --include='*.tsx' --include='*.ts' --include='*.jsx' --include='*.js'",
929
+ "",
930
+ "# 搜索自定义 Hooks(以 use 开头的函数调用)",
931
+ "grep -rn 'use[A-Z][a-zA-Z]*\\s*(' src/ --include='*.tsx' --include='*.ts' --include='*.jsx' --include='*.js' | grep -v 'node_modules'",
932
+ "```",
933
+ "",
934
+ "**第三步:统计覆盖范围**",
935
+ "```bash",
936
+ "# 统计包含 Hooks 的文件总数",
937
+ "grep -rl 'use[A-Z]' src/ --include='*.tsx' --include='*.ts' | wc -l",
938
+ "",
939
+ "# 按目录统计 Hooks 文件分布",
940
+ "grep -rl 'use[A-Z]' src/ --include='*.tsx' --include='*.ts' | sed 's|/[^/]*$||' | sort | uniq -c | sort -rn",
941
+ "```",
942
+ "",
943
+ "**产出格式**:",
944
+ "```",
945
+ "total_files_with_hooks: <数量>",
946
+ "directories_scanned: [<列出所有扫描的目录>]",
947
+ "hooks_files_by_dir: { 'src/pages/xxx': N, 'src/components/xxx': N, ... }",
948
+ "custom_hooks_found: [<列出所有自定义 Hook 名称>]",
949
+ "```",
950
+ ].join("\n"),
951
+ suggestedTools: ["Bash", "Read"],
952
+ output: "所有 Hooks 调用位置的完整清单,按目录分组",
953
+ timeout: 30000,
535
954
  },
536
955
  {
537
956
  id: "check-top-level",
538
- description: "检查 Hooks 是否在顶层调用(不在条件/循环中)",
539
- type: "simple",
540
- timeout: 10000,
957
+ title: "检查 Hooks 顶层调用规则",
958
+ instruction: [
959
+ "## 检查 Hooks 是否在顶层调用",
960
+ "",
961
+ "基于 `scan-all-hooks` 的结果,逐个检查每个 Hooks 调用是否违反顶层调用规则。",
962
+ "",
963
+ "**检查项**:",
964
+ "1. Hooks 不在 `if/else` 条件分支中调用",
965
+ "2. Hooks 不在 `for/while` 循环中调用",
966
+ "3. Hooks 不在嵌套函数(回调、事件处理器内部)中调用",
967
+ "4. Hooks 不在 `try/catch` 块中调用",
968
+ "",
969
+ "**执行方式**:",
970
+ "```bash",
971
+ "# 对每个包含 Hooks 的文件,用 Read 工具读取并人工检查上下文",
972
+ "# 重点检查 Hooks 调用是否在条件/循环/嵌套函数内",
973
+ "```",
974
+ "",
975
+ "**产出格式**:",
976
+ "```",
977
+ "violations: [",
978
+ " { file: 'src/pages/xxx/index.tsx', line: 42, hook: 'useState', issue: '在 if 条件内调用' }",
979
+ "]",
980
+ "```",
981
+ ].join("\n"),
982
+ suggestedTools: ["Bash", "Read"],
983
+ output: "违反顶层调用规则的位置清单",
984
+ depends: ["scan-all-hooks"],
985
+ timeout: 20000,
541
986
  },
542
987
  {
543
988
  id: "audit-deps-arrays",
544
- description: "检查 useEffect/useMemo/useCallback 依赖数组完整性",
545
- type: "simple",
546
- timeout: 15000,
989
+ title: "审查依赖数组完整性",
990
+ instruction: [
991
+ "## 检查 useEffect/useMemo/useCallback 依赖数组",
992
+ "",
993
+ "**执行方式**:",
994
+ "```bash",
995
+ "# 找到所有 useEffect/useMemo/useCallback 调用及其依赖数组",
996
+ "grep -rn 'useEffect\\|useMemo\\|useCallback' src/ --include='*.tsx' --include='*.ts' -A 5",
997
+ "```",
998
+ "",
999
+ "**检查项**:",
1000
+ "1. 依赖数组是否遗漏了回调/计算中使用的变量",
1001
+ "2. 是否有意忽略了某些依赖(如果有 eslint-disable 注释,检查是否合理)",
1002
+ "3. 对象/数组依赖是否因引用变化导致不必要的重执行",
1003
+ "4. 函数依赖是否应该用 useCallback 包裹",
1004
+ "",
1005
+ "**产出格式**:",
1006
+ "```",
1007
+ "missing_deps: [",
1008
+ " { file: '...', line: N, hook: 'useEffect', missing: ['userId'], current: [] }",
1009
+ "]",
1010
+ "unnecessary_deps: [...]",
1011
+ "```",
1012
+ ].join("\n"),
1013
+ suggestedTools: ["Bash", "Read"],
1014
+ output: "依赖数组问题清单(缺失/多余/不稳定依赖)",
1015
+ depends: ["scan-all-hooks"],
1016
+ timeout: 20000,
547
1017
  },
548
1018
  {
549
1019
  id: "audit-cleanups",
550
- description: "检查 useEffect 是否有缺少的清理函数",
551
- type: "simple",
552
- timeout: 10000,
1020
+ title: "审查 useEffect 清理函数",
1021
+ instruction: [
1022
+ "## 检查 useEffect 清理函数",
1023
+ "",
1024
+ "**检查项**:",
1025
+ "1. 使用了订阅(addEventListener、subscribe)的 useEffect 是否有清理函数",
1026
+ "2. 使用了定时器(setTimeout、setInterval)的 useEffect 是否在清理中清除",
1027
+ "3. 使用了异步请求的 useEffect 是否有 AbortController 或取消标记",
1028
+ "4. WebSocket 连接是否在清理函数中关闭",
1029
+ "",
1030
+ "**执行方式**:",
1031
+ "```bash",
1032
+ "# 找到包含副作用但可能缺少清理的 useEffect",
1033
+ "grep -rn 'useEffect' src/ --include='*.tsx' --include='*.ts' -A 10 | grep -E 'addEventListener|subscribe|setTimeout|setInterval|fetch|WebSocket|connect'",
1034
+ "```",
1035
+ "",
1036
+ "**产出格式**:",
1037
+ "```",
1038
+ "missing_cleanup: [",
1039
+ " { file: '...', line: N, side_effect: 'addEventListener', description: '缺少 removeEventListener 清理' }",
1040
+ "]",
1041
+ "```",
1042
+ ].join("\n"),
1043
+ suggestedTools: ["Bash", "Read"],
1044
+ output: "缺少清理函数的 useEffect 清单",
1045
+ depends: ["scan-all-hooks"],
1046
+ timeout: 15000,
553
1047
  },
554
1048
  {
555
1049
  id: "detect-anti-patterns",
556
- description: "检测反模式(在渲染中创建组件、不必要的 useState、过大的 useEffect)",
557
- type: "llm",
1050
+ title: "检测 React 反模式",
1051
+ instruction: [
1052
+ "## 检测 React 反模式",
1053
+ "",
1054
+ "基于 `scan-all-hooks` 的完整文件列表,检测以下反模式:",
1055
+ "",
1056
+ "**反模式清单**:",
1057
+ "1. **渲染中创建组件** — 在函数体内部定义 `function` 或 `const Component = () =>`",
1058
+ "2. **不必要的 useState** — 可以用计算值替代的状态(如 `const [full, setFull] = useState(first + last)`)",
1059
+ "3. **过大的 useEffect** — 单个 useEffect 超过 20 行,应拆分",
1060
+ "4. **useEffect 作为事件处理器** — 用 useEffect 响应事件而非用事件处理函数",
1061
+ "5. **直接修改 state** — `state.xxx = yyy` 而非 `setState`",
1062
+ "6. **key 使用 index** — 列表渲染使用数组 index 作为 key",
1063
+ "",
1064
+ "**执行方式**:",
1065
+ "```bash",
1066
+ "# 检测渲染中定义组件",
1067
+ "grep -rn 'const [A-Z].*= () =>\\|function [A-Z]' src/ --include='*.tsx' | grep -v '^.*:.*export'",
1068
+ "",
1069
+ "# 检测 key={index} 模式",
1070
+ "grep -rn 'key={.*index\\|key={.*i}' src/ --include='*.tsx'",
1071
+ "```",
1072
+ "",
1073
+ "**产出格式**:",
1074
+ "```",
1075
+ "anti_patterns: [",
1076
+ " { file: '...', line: N, type: 'component-in-render', severity: 'Critical', description: '...' }",
1077
+ "]",
1078
+ "```",
1079
+ ].join("\n"),
1080
+ suggestedTools: ["Bash", "Read"],
1081
+ output: "反模式清单,按 Critical/Warning/Suggestion 分级",
558
1082
  depends: ["scan-all-hooks"],
559
- timeout: 15000,
1083
+ timeout: 20000,
560
1084
  },
561
1085
  {
562
1086
  id: "generate-review-report",
563
- description: "生成审查报告,标注 Critical/Warning/Suggestion 等级",
564
- type: "llm",
1087
+ title: "生成审查报告",
1088
+ instruction: [
1089
+ "## 生成 Hooks 审查报告",
1090
+ "",
1091
+ "汇总所有检查结果,生成结构化报告。",
1092
+ "",
1093
+ "**报告格式**:",
1094
+ "```",
1095
+ "## React Hooks 审查报告",
1096
+ "",
1097
+ "### 扫描覆盖",
1098
+ "- 扫描目录:<列出所有目录>",
1099
+ "- 扫描文件数:<N>",
1100
+ "- 发现 Hooks 调用总数:<N>",
1101
+ "",
1102
+ "### Critical(必须修复)",
1103
+ "| 文件 | 行号 | 问题 | 描述 |",
1104
+ "|------|------|------|------|",
1105
+ "| src/pages/xxx | 42 | 条件调用 Hook | useState 在 if 内调用 |",
1106
+ "",
1107
+ "### Warning(建议修复)",
1108
+ "| 文件 | 行号 | 问题 | 描述 |",
1109
+ "|------|------|------|------|",
1110
+ "",
1111
+ "### Suggestion(可选优化)",
1112
+ "| 文件 | 行号 | 问题 | 描述 |",
1113
+ "|------|------|------|------|",
1114
+ "```",
1115
+ ].join("\n"),
1116
+ suggestedTools: ["Read"],
1117
+ output: "分优先级的完整审查报告",
565
1118
  depends: ["check-top-level", "audit-deps-arrays", "audit-cleanups", "detect-anti-patterns"],
566
1119
  timeout: 20000,
567
1120
  },
568
1121
  {
569
1122
  id: "auto-fix-safe",
570
- description: "自动修复安全的问题(补充缺失依赖、添加清理函数)",
571
- type: "llm",
1123
+ title: "自动修复安全问题",
1124
+ instruction: [
1125
+ "## 自动修复安全的 Hooks 问题",
1126
+ "",
1127
+ "**可安全自动修复的问题**:",
1128
+ "1. 补充 useEffect/useMemo/useCallback 缺失的依赖项",
1129
+ "2. 为缺少清理的 useEffect 添加清理函数骨架",
1130
+ "3. 将 `key={index}` 改为使用唯一标识符",
1131
+ "",
1132
+ "**不可自动修复(需人工判断)**:",
1133
+ "- 条件调用 Hook — 需要重构逻辑",
1134
+ "- 反模式 — 需要理解业务意图",
1135
+ "",
1136
+ "**执行方式**:使用 Edit 工具逐个修复,每次修改后确认不影响周围代码。",
1137
+ ].join("\n"),
1138
+ suggestedTools: ["Read", "Edit"],
1139
+ output: "修复的 diff 列表",
572
1140
  depends: ["generate-review-report"],
573
- timeout: 20000,
1141
+ timeout: 30000,
574
1142
  },
575
1143
  {
576
1144
  id: "verify-fixes",
577
- description: "运行 ESLint hooks 插件和类型检查确认修复",
578
- type: "simple",
1145
+ title: "验证修复",
1146
+ instruction: [
1147
+ "## 验证修复结果",
1148
+ "",
1149
+ "**执行动作**:",
1150
+ "1. 运行 TypeScript 类型检查:`npx tsc --noEmit`",
1151
+ "2. 运行 ESLint(如有 hooks 插件):`npx eslint src/ --ext .tsx,.ts`",
1152
+ "3. 运行项目测试:`npm test`",
1153
+ "4. 确认所有修复未引入新问题",
1154
+ ].join("\n"),
1155
+ suggestedTools: ["Bash"],
1156
+ output: "验证结果(类型检查/ESLint/测试)",
579
1157
  depends: ["auto-fix-safe"],
580
1158
  timeout: 30000,
581
1159
  },
582
1160
  {
583
1161
  id: "approve-fixes",
584
- description: "人工审查高风险修复项",
585
- type: "manual",
1162
+ title: "人工审查修复",
1163
+ instruction: [
1164
+ "## 人工审查高风险修复项",
1165
+ "",
1166
+ "将所有修复呈现给用户,等待确认。展示每个修复的 diff 和原因。",
1167
+ "",
1168
+ "**注意**:此步骤必须等待用户明确确认后才能继续。",
1169
+ ].join("\n"),
1170
+ suggestedTools: ["Read"],
1171
+ output: "用户确认结果",
586
1172
  depends: ["verify-fixes"],
1173
+ requiresUserConfirmation: true,
587
1174
  timeout: 120000,
588
1175
  },
589
1176
  ],
@@ -596,55 +1183,276 @@ export const reactPlugin = {
596
1183
  {
597
1184
  name: "component-refactor",
598
1185
  description: "组件重构:复杂度评估 → 拆分建议 → 安全重构",
599
- version: "1.0.0",
1186
+ version: "2.0.0",
600
1187
  steps: [
601
1188
  {
602
1189
  id: "analyze-complexity",
603
- description: "分析组件复杂度(行数、props 数量、Hooks 数量、嵌套层级)",
604
- type: "simple",
605
- timeout: 10000,
1190
+ title: "分析组件复杂度",
1191
+ instruction: [
1192
+ "## 分析组件复杂度",
1193
+ "",
1194
+ "量化评估目标组件的复杂度指标。",
1195
+ "",
1196
+ "**执行动作**:",
1197
+ "1. 统计组件的基础指标:",
1198
+ " ```bash",
1199
+ " # 文件行数",
1200
+ " wc -l <component_file>",
1201
+ " # Props 数量",
1202
+ " grep -c '^\\s*\\w*\\?:' <component_file> # 统计 interface 中的字段",
1203
+ " # Hooks 调用数量",
1204
+ " grep -c 'use[A-Z]' <component_file>",
1205
+ " # JSX 嵌套层级",
1206
+ " # 手动检查或通过缩进层级判断",
1207
+ " ```",
1208
+ "2. 统计分支复杂度:",
1209
+ " ```bash",
1210
+ " grep -c 'if\\|else\\|switch\\|case\\|?\\|&&\\|||' <component_file>",
1211
+ " ```",
1212
+ "3. 统计 useEffect 数量和处理逻辑行数",
1213
+ "4. 评估组件职责数量(渲染 + 数据获取 + 状态管理 + 副作用)",
1214
+ "",
1215
+ "**复杂度评级标准**:",
1216
+ "- **A 级(简单)**:< 100 行,< 5 个 props,< 3 个 hooks",
1217
+ "- **B 级(中等)**:100-300 行,5-10 个 props,3-5 个 hooks",
1218
+ "- **C 级(复杂)**:300-500 行,>10 个 props,>5 个 hooks",
1219
+ "- **D 级(巨型)**:>500 行,需要拆分",
1220
+ "",
1221
+ "**产出格式**:",
1222
+ "```",
1223
+ "file: <path>",
1224
+ "lines: <N>",
1225
+ "props_count: <N>",
1226
+ "hooks_count: <N>",
1227
+ "use_effect_count: <N>",
1228
+ "branch_count: <N>",
1229
+ "responsibilities: ['rendering', 'data-fetching', 'state-management', 'side-effects']",
1230
+ "complexity_grade: A|B|C|D",
1231
+ "refactor_needed: true|false",
1232
+ "```",
1233
+ ].join("\n"),
1234
+ suggestedTools: ["Bash", "Read"],
1235
+ output: "组件复杂度指标和评级",
606
1236
  },
607
1237
  {
608
1238
  id: "identify-smells",
609
- description: "识别代码异味(巨型组件、重复逻辑、过度耦合、魔法数字)",
610
- type: "llm",
1239
+ title: "识别代码异味",
1240
+ instruction: [
1241
+ "## 识别组件代码异味",
1242
+ "",
1243
+ "基于 `analyze-complexity` 的分析结果,识别代码异味。",
1244
+ "",
1245
+ "**检查项**:",
1246
+ "1. **巨型组件** — 单文件 >300 行,承担多个职责",
1247
+ "2. **重复逻辑** — 组件内有 >20 行相似的 JSX 或逻辑",
1248
+ " ```bash",
1249
+ " # 检查是否有重复的 JSX 片段",
1250
+ " grep -n 'className=' <component_file> | head -20",
1251
+ " ```",
1252
+ "3. **过度耦合** — 组件直接访问多个外部状态(Context、Store、API)",
1253
+ " ```bash",
1254
+ " grep -n 'useContext\\|useSelector\\|useStore\\|fetch\\|axios' <component_file>",
1255
+ " ```",
1256
+ "4. **魔法数字/字符串** — 硬编码的数值、URL、配置值",
1257
+ " ```bash",
1258
+ " grep -nE '[0-9]{2,}|\"http[s]?://' <component_file>",
1259
+ " ```",
1260
+ "5. **深层嵌套** — 条件嵌套 >3 层",
1261
+ "6. **超长 Props** — interface 字段 >10 个",
1262
+ "7. **useEffect 滥用** — 用 useEffect 替代事件处理器",
1263
+ "",
1264
+ "**产出格式**:",
1265
+ "```",
1266
+ "smells: [",
1267
+ " { type: 'giant-component'|'duplication'|'coupling'|'magic-number'|'deep-nesting'|'long-props'|'useeffect-abuse',",
1268
+ " location: '<file>:<line>', severity: 'critical'|'warning'|'info',",
1269
+ " description: '...' }",
1270
+ "]",
1271
+ "```",
1272
+ ].join("\n"),
1273
+ suggestedTools: ["Bash", "Read"],
1274
+ output: "代码异味清单(按严重程度排序)",
611
1275
  depends: ["analyze-complexity"],
612
- timeout: 15000,
613
1276
  },
614
1277
  {
615
1278
  id: "propose-split",
616
- description: "生成拆分方案(提取子组件、抽取自定义 Hooks、提取工具函数)",
617
- type: "llm",
1279
+ title: "生成拆分方案",
1280
+ instruction: [
1281
+ "## 生成组件拆分方案",
1282
+ "",
1283
+ "基于 `identify-smells` 的结果,设计重构方案。",
1284
+ "",
1285
+ "**拆分策略**:",
1286
+ "1. **提取子组件** — 将独立的 UI 片段拆分为子组件",
1287
+ " - 识别可独立的 JSX 块(有明确的 props 边界)",
1288
+ " - 子组件命名:`<Parent><Child/></Parent>`",
1289
+ "2. **抽取自定义 Hooks** — 将逻辑从渲染中分离",
1290
+ " - 数据获取逻辑 → `useXxxData`",
1291
+ " - 表单逻辑 → `useXxxForm`",
1292
+ " - UI 状态逻辑 → `useXxxUI`",
1293
+ "3. **提取工具函数** — 将纯计算逻辑提取到 utils",
1294
+ "",
1295
+ "**执行动作**:",
1296
+ "1. 用 Read 工具仔细阅读组件全文",
1297
+ "2. 识别逻辑边界和可拆分的代码块",
1298
+ "3. 设计新文件结构:",
1299
+ " ```bash",
1300
+ " # 查看当前目录结构",
1301
+ " ls -la <component_dir>/",
1302
+ " ```",
1303
+ "4. 设计每个子组件 / Hook 的 Props 和返回值",
1304
+ "",
1305
+ "**产出格式**:",
1306
+ "```",
1307
+ "split_plan: {",
1308
+ " sub_components: [{ name: 'XxxHeader', responsibility: '...', props: {...} }],",
1309
+ " custom_hooks: [{ name: 'useXxxData', responsibility: '...', returns: {...} }],",
1310
+ " utils: [{ name: 'formatXxx', responsibility: '...' }],",
1311
+ " new_file_structure: ['Xxx/index.tsx', 'Xxx/XxxHeader.tsx', 'Xxx/useXxxData.ts']",
1312
+ "}",
1313
+ "```",
1314
+ ].join("\n"),
1315
+ suggestedTools: ["Read", "Bash"],
1316
+ output: "组件拆分方案(子组件、自定义 Hooks、工具函数)",
618
1317
  depends: ["identify-smells"],
619
- timeout: 20000,
620
1318
  },
621
1319
  {
622
1320
  id: "extract-hooks",
623
- description: "抽取可复用逻辑为自定义 Hooks",
624
- type: "llm",
1321
+ title: "抽取自定义 Hooks",
1322
+ instruction: [
1323
+ "## 抽取可复用逻辑为自定义 Hooks",
1324
+ "",
1325
+ "按照 `propose-split` 的方案,将逻辑提取为自定义 Hooks。",
1326
+ "",
1327
+ "**执行动作**:",
1328
+ "1. 对每个计划中的自定义 Hook:",
1329
+ " - 创建 Hook 文件:`src/hooks/useXxx.ts` 或组件旁的 `useXxx.ts`",
1330
+ " - 从原组件中剪切对应逻辑",
1331
+ " - 使用 Edit 工具在原位置替换为 Hook 调用",
1332
+ "2. Hook 编写规范:",
1333
+ " - 以 `use` 开头命名",
1334
+ " - 返回值使用对象形式 `{ data, loading, error }`",
1335
+ " - 入参使用对象形式 `{ userId, options }`",
1336
+ " - 添加 TypeScript 类型定义(入参和返回值)",
1337
+ "3. 更新原组件的 import",
1338
+ "4. 确保 Hook 符合 Hooks 规则(顶层调用、不嵌套)",
1339
+ "",
1340
+ "**产出格式**:",
1341
+ "```",
1342
+ "hooks_extracted: [{ name, file_path, params: {...}, returns: {...} }]",
1343
+ "original_component_changes: [{ file, line_range, description }]",
1344
+ "```",
1345
+ ].join("\n"),
1346
+ suggestedTools: ["Read", "Edit", "Write"],
1347
+ output: "提取的自定义 Hooks 清单",
625
1348
  depends: ["propose-split"],
626
- timeout: 15000,
627
1349
  },
628
1350
  {
629
1351
  id: "extract-components",
630
- description: "拆分子组件并更新引用",
631
- type: "llm",
1352
+ title: "拆分子组件",
1353
+ instruction: [
1354
+ "## 拆分子组件并更新引用",
1355
+ "",
1356
+ "按照 `propose-split` 的方案,将 UI 片段拆分为子组件。",
1357
+ "",
1358
+ "**执行动作**:",
1359
+ "1. 对每个计划中的子组件:",
1360
+ " - 创建组件文件",
1361
+ " - 从父组件中剪切对应 JSX 和相关逻辑",
1362
+ " - 使用 Edit 工具在父组件中替换为子组件调用",
1363
+ "2. 子组件编写规范:",
1364
+ " - 函数组件 + Hooks",
1365
+ " - Props 使用 interface 定义",
1366
+ " - 纯展示组件用 `React.memo` 包裹",
1367
+ " - 导出方式:`export function XxxComponent(props: XxxProps) {}`",
1368
+ "3. 更新父组件的 import 和 JSX",
1369
+ "4. 检查子组件是否需要传递事件处理器(回调 Props)",
1370
+ "",
1371
+ "**产出格式**:",
1372
+ "```",
1373
+ "components_extracted: [{ name, file_path, props: {...}, parent: '...' }]",
1374
+ "parent_component_changes: [{ file, imports_updated: [...], jsx_updated: true|false }]",
1375
+ "```",
1376
+ ].join("\n"),
1377
+ suggestedTools: ["Read", "Edit", "Write"],
1378
+ output: "拆分出的子组件清单和父组件变更",
632
1379
  depends: ["propose-split"],
633
- timeout: 20000,
634
1380
  },
635
1381
  {
636
1382
  id: "update-imports",
637
- description: "更新所有依赖此组件的 import 路径",
638
- type: "simple",
1383
+ title: "更新依赖引用",
1384
+ instruction: [
1385
+ "## 更新所有依赖此组件的 import 路径",
1386
+ "",
1387
+ "**执行动作**:",
1388
+ "1. 查找所有导入了原组件的文件:",
1389
+ " ```bash",
1390
+ " grep -rn \"from.*<original_component_path>\" src/ --include='*.tsx' --include='*.ts' --include='*.jsx' --include='*.js'",
1391
+ " ```",
1392
+ "2. 对每个引用文件:",
1393
+ " - 检查是否需要更新 import 路径(组件拆分后文件位置变化)",
1394
+ " - 检查是否需要拆分 import(原来一个组件现在变成了多个)",
1395
+ " - 使用 Edit 工具精准修改 import 语句",
1396
+ "3. 检查是否有 barrel file(index.ts)需要更新:",
1397
+ " ```bash",
1398
+ " find src/components/ -name 'index.ts' | head -10",
1399
+ " ```",
1400
+ "4. 检查 Storybook stories 是否需要更新:",
1401
+ " ```bash",
1402
+ " find . -name '*.stories.*' | head -10",
1403
+ " ```",
1404
+ "",
1405
+ "**产出格式**:",
1406
+ "```",
1407
+ "imports_updated: [{ file, old_import: '...', new_import: '...' }]",
1408
+ "barrel_files_updated: [{ path }]",
1409
+ "stories_updated: [{ path }]",
1410
+ "```",
1411
+ ].join("\n"),
1412
+ suggestedTools: ["Bash", "Read", "Edit"],
1413
+ output: "更新的 import 清单",
639
1414
  depends: ["extract-components"],
640
- timeout: 10000,
641
1415
  },
642
1416
  {
643
1417
  id: "regression-test",
644
- description: "运行回归测试确保重构后行为一致",
645
- type: "simple",
1418
+ title: "运行回归测试",
1419
+ instruction: [
1420
+ "## 运行回归测试确保重构后行为一致",
1421
+ "",
1422
+ "**执行动作**:",
1423
+ "1. 运行 TypeScript 类型检查:",
1424
+ " ```bash",
1425
+ " npx tsc --noEmit",
1426
+ " ```",
1427
+ "2. 运行与重构组件相关的测试:",
1428
+ " ```bash",
1429
+ " # 找到相关测试文件",
1430
+ " find src/ -name '*.test.*' -o -name '*.spec.*' | grep -i '<component_name>'",
1431
+ " # 运行相关测试",
1432
+ " npx vitest run <test_files>",
1433
+ " ```",
1434
+ "3. 运行完整测试套件确认无回归:",
1435
+ " ```bash",
1436
+ " npm test 2>&1",
1437
+ " ```",
1438
+ "4. 分析测试结果:",
1439
+ " - 全部通过 → ✅ 重构成功",
1440
+ " - 有失败 → 分析是测试需要更新还是重构引入了 Bug",
1441
+ "5. 如果测试失败是因为 import 路径变化,更新测试文件中的 import",
1442
+ "",
1443
+ "**产出格式**:",
1444
+ "```",
1445
+ "type_check: passed | failed",
1446
+ "test_result: passed | failed",
1447
+ "tests_run: <N>",
1448
+ "tests_passed: <N>",
1449
+ "tests_failed: <N>",
1450
+ "fixes_needed: [{ file, issue: '...' }]",
1451
+ "```",
1452
+ ].join("\n"),
1453
+ suggestedTools: ["Bash", "Read", "Edit"],
1454
+ output: "回归测试结果",
646
1455
  depends: ["extract-hooks", "extract-components", "update-imports"],
647
- timeout: 60000,
648
1456
  },
649
1457
  ],
650
1458
  triggers: [
@@ -660,58 +1468,198 @@ export const reactPlugin = {
660
1468
  steps: [
661
1469
  {
662
1470
  id: "check-existing",
663
- description: "检查是否有可复用的现有组件",
664
- type: "simple",
665
- timeout: 5000,
1471
+ title: "检查可复用组件",
1472
+ instruction: [
1473
+ "## 检查是否有可复用的现有组件",
1474
+ "",
1475
+ "避免创建功能重复的组件。",
1476
+ "",
1477
+ "**执行动作**:",
1478
+ "1. 搜索项目中是否已有功能相似的组件:",
1479
+ " ```bash",
1480
+ " # 列出所有组件",
1481
+ " find src/components/ -type f -name '*.tsx' | head -50",
1482
+ " # 按关键词搜索(根据用户需求中的关键词)",
1483
+ " find src/ -type f -name '*.tsx' | xargs grep -l '<keyword>' 2>/dev/null",
1484
+ " ```",
1485
+ "2. 检查组件库(如有 UI 库如 antd / MUI):",
1486
+ " ```bash",
1487
+ " grep -rn \"from 'antd'\\|from '@mui'\" src/ --include='*.tsx' --include='*.ts' | head -10",
1488
+ " ```",
1489
+ "3. 检查是否有类似的 Storybook stories 或文档:",
1490
+ " ```bash",
1491
+ " find . -name '*.stories.*' | head -10",
1492
+ " ```",
1493
+ "4. 如果找到相似组件,评估是否可以直接复用、扩展或作为参考",
1494
+ "",
1495
+ "**产出格式**:",
1496
+ "```",
1497
+ "similar_components: [{ name, path, similarity: 'high'|'medium'|'low', reuse_approach: 'direct'|'extend'|'reference'|'create_new' }]",
1498
+ "ui_library_available: true|false",
1499
+ "decision: create_new | extend_existing",
1500
+ "```",
1501
+ ].join("\n"),
1502
+ suggestedTools: ["Bash", "Read"],
1503
+ output: "可复用组件清单和复用决策",
666
1504
  },
667
1505
  {
668
1506
  id: "define-props",
669
- description: "根据需求定义 TypeScript Props interface",
670
- type: "llm",
671
- timeout: 10000,
1507
+ title: "定义 Props 类型",
1508
+ instruction: [
1509
+ "## 根据需求定义 TypeScript Props interface",
1510
+ "",
1511
+ "**执行动作**:",
1512
+ "1. 分析组件需要的 Props:",
1513
+ " - 数据 Props(传入组件的内容)",
1514
+ " - 回调 Props(事件处理器)",
1515
+ " - 样式 Props(className、style)",
1516
+ " - 子组件 Props(children)",
1517
+ "2. 遵循项目约定:",
1518
+ " - 使用 `interface` 定义(不用 `type`)",
1519
+ " - 接口命名:`XxxProps`",
1520
+ " - 必填 Props 在前,可选 Props 在后",
1521
+ " - 可选 Props 使用 `?:` 标记",
1522
+ "3. 为每个 Prop 添加 JSDoc 注释",
1523
+ "4. 使用 React 内置类型:",
1524
+ " - `React.ReactNode` 用于 children",
1525
+ " - `React.CSSProperties` 用于 style",
1526
+ " - 事件类型:`React.MouseEventHandler<HTMLButtonElement>`",
1527
+ "",
1528
+ "**产出格式**:",
1529
+ "```typescript",
1530
+ "interface XxxProps {",
1531
+ " /** 数据描述 */",
1532
+ " data: DataType;",
1533
+ " /** 点击回调 */",
1534
+ " onClick?: () => void;",
1535
+ " /** 自定义类名 */",
1536
+ " className?: string;",
1537
+ "}",
1538
+ "```",
1539
+ ].join("\n"),
1540
+ suggestedTools: ["Read", "Write"],
1541
+ output: "TypeScript Props interface 定义",
672
1542
  },
673
1543
  {
674
1544
  id: "create-component",
675
- description: "生成组件代码(含 React.memo、错误处理、加载状态)",
676
- type: "llm",
1545
+ title: "生成组件代码",
1546
+ instruction: [
1547
+ "## 生成组件代码",
1548
+ "",
1549
+ "基于 `define-props` 的类型定义生成组件实现。",
1550
+ "",
1551
+ "**执行动作**:",
1552
+ "1. 创建组件文件(遵循项目目录约定):",
1553
+ " ```bash",
1554
+ " # 确认组件应该放在哪个目录",
1555
+ " ls -la src/components/ 2>/dev/null",
1556
+ " ```",
1557
+ "2. 组件结构模板:",
1558
+ " - 导入依赖",
1559
+ " - Props interface(如已单独定义则 import)",
1560
+ " - 组件函数(含默认值 / 解构)",
1561
+ " - 状态和副作用(Hooks)",
1562
+ " - 事件处理器",
1563
+ " - 返回 JSX",
1564
+ " - export",
1565
+ "3. 质量要求:",
1566
+ " - 函数组件(无 Class)",
1567
+ " - `React.memo` 包裹纯展示组件",
1568
+ " - 错误处理:loading / error / empty 状态",
1569
+ " - 无 `any` 类型",
1570
+ " - 有意义的组件命名",
1571
+ "4. 使用 `React.memo` + `useMemo` / `useCallback`(仅当有性能收益时)",
1572
+ "",
1573
+ "**产出格式**:",
1574
+ "```",
1575
+ "component_file: <path>",
1576
+ "component_name: <name>",
1577
+ "has_memo: true|false",
1578
+ "has_error_handling: true|false",
1579
+ "hooks_used: ['useState', 'useEffect', ...]",
1580
+ "```",
1581
+ ].join("\n"),
1582
+ suggestedTools: ["Read", "Write", "Edit"],
1583
+ output: "生成的组件文件",
677
1584
  depends: ["define-props"],
678
- timeout: 15000,
679
1585
  },
680
1586
  {
681
1587
  id: "create-styles",
682
- description: "生成 CSS Module 样式文件",
683
- type: "llm",
1588
+ title: "生成样式文件",
1589
+ instruction: [
1590
+ "## 生成样式文件",
1591
+ "",
1592
+ "**执行动作**:",
1593
+ "1. 确认项目使用的样式方案:",
1594
+ " ```bash",
1595
+ " # 检查 tailwind / CSS Modules / styled-components 等",
1596
+ " cat package.json | grep -i 'tailwind\\|styled-components\\|emotion'",
1597
+ " find src/ -name '*.module.css' | head -5",
1598
+ " find src/ -name '*.module.scss' | head -5",
1599
+ " ```",
1600
+ "2. 按项目约定创建样式文件:",
1601
+ " - **CSS Modules**:`Xxx.module.css`",
1602
+ " - **Tailwind**:直接使用 class 名",
1603
+ " - **styled-components**:在组件文件内或单独文件",
1604
+ "3. 样式质量要求:",
1605
+ " - 响应式设计(至少支持 mobile / desktop)",
1606
+ " - 使用 CSS 变量(如项目有设计系统)",
1607
+ " - 避免硬编码的颜色值",
1608
+ " - 命名规范:kebab-case(CSS Modules)或 camelCase(CSS-in-JS)",
1609
+ "4. 在组件中导入样式",
1610
+ "",
1611
+ "**产出格式**:",
1612
+ "```",
1613
+ "style_file: <path>",
1614
+ "style_approach: 'css-modules'|'tailwind'|'styled-components'|'inline'",
1615
+ "responsive: true|false",
1616
+ "```",
1617
+ ].join("\n"),
1618
+ suggestedTools: ["Bash", "Read", "Write"],
1619
+ output: "生成的样式文件",
684
1620
  depends: ["create-component"],
685
- timeout: 5000,
686
1621
  },
687
1622
  {
688
1623
  id: "create-tests",
689
- description: "生成测试文件(渲染测试、交互测试、快照测试)",
690
- type: "llm",
1624
+ title: "生成测试文件",
1625
+ instruction: [
1626
+ "## 生成组件测试文件",
1627
+ "",
1628
+ "**执行动作**:",
1629
+ "1. 确认项目的测试框架和约定:",
1630
+ " ```bash",
1631
+ " # 检查测试框架",
1632
+ " cat package.json | grep -i 'vitest\\|jest\\|testing-library'",
1633
+ " # 检查测试目录约定",
1634
+ " find src/ -type d -name '__tests__' | head -5",
1635
+ " find src/ -name '*.test.*' -o -name '*.spec.*' | head -5",
1636
+ " ```",
1637
+ "2. 创建测试文件(与组件同目录或 __tests__ 目录)",
1638
+ "3. 测试用例清单:",
1639
+ " - **渲染测试**:默认 Props 下组件正确渲染",
1640
+ " - **Props 测试**:不同 Props 组合的渲染结果",
1641
+ " - **交互测试**:点击、输入等用户操作",
1642
+ " - **边界测试**:空数据、错误状态、loading 状态",
1643
+ " - **快照测试**(可选):`expect(component).toMatchSnapshot()`",
1644
+ "4. Mock 策略:",
1645
+ " - API 调用使用 `vi.mock` / `jest.mock`",
1646
+ " - Context 使用 wrapper",
1647
+ " - 路由使用 `MemoryRouter`",
1648
+ "",
1649
+ "**产出格式**:",
1650
+ "```",
1651
+ "test_file: <path>",
1652
+ "test_count: <N>",
1653
+ "test_cases: [{ describe: '...', it: '...' }]",
1654
+ "```",
1655
+ ].join("\n"),
1656
+ suggestedTools: ["Bash", "Read", "Write"],
1657
+ output: "生成的测试文件",
691
1658
  depends: ["create-component"],
692
- timeout: 15000,
693
- },
694
- {
695
- id: "type-check",
696
- description: "TypeScript 类型检查",
697
- type: "simple",
698
- depends: ["create-component", "create-styles"],
699
- timeout: 10000,
700
- },
701
- {
702
- id: "lint-check",
703
- description: "运行 ESLint 检查",
704
- type: "simple",
705
- depends: ["type-check"],
706
- timeout: 10000,
707
- },
708
- {
709
- id: "run-tests",
710
- description: "运行组件测试",
711
- type: "simple",
712
- depends: ["create-tests", "lint-check"],
713
- timeout: 15000,
714
1659
  },
1660
+ { id: "type-check", stepTemplate: "type-check", depends: ["create-component", "create-styles"] },
1661
+ { id: "lint-check", stepTemplate: "lint-check", depends: ["type-check"] },
1662
+ { id: "run-tests", stepTemplate: "run-tests", depends: ["create-tests", "lint-check"] },
715
1663
  ],
716
1664
  triggers: [
717
1665
  { type: "cli", command: "new:component" },