@pageai/ralph-loop 1.0.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.
Files changed (120) hide show
  1. package/.agent/PROMPT.md +58 -0
  2. package/.agent/STEERING.md +3 -0
  3. package/.agent/logs/LOG.md +13 -0
  4. package/.agent/prd/.gitkeep +0 -0
  5. package/.agent/screenshots/.gitkeep +0 -0
  6. package/.agent/skills/component-refactoring/SKILL.md +247 -0
  7. package/.agent/skills/component-refactoring/references/complexity-patterns.md +485 -0
  8. package/.agent/skills/component-refactoring/references/component-splitting.md +419 -0
  9. package/.agent/skills/component-refactoring/references/hook-extraction.md +317 -0
  10. package/.agent/skills/e2e-tester/SKILL.md +595 -0
  11. package/.agent/skills/frontend-code-review/SKILL.md +73 -0
  12. package/.agent/skills/frontend-code-review/references/code-quality.md +28 -0
  13. package/.agent/skills/frontend-code-review/references/performance.md +36 -0
  14. package/.agent/skills/frontend-testing/SKILL.md +316 -0
  15. package/.agent/skills/frontend-testing/assets/component-test.template.tsx +293 -0
  16. package/.agent/skills/frontend-testing/assets/hook-test.template.ts +207 -0
  17. package/.agent/skills/frontend-testing/assets/utility-test.template.ts +154 -0
  18. package/.agent/skills/frontend-testing/references/async-testing.md +345 -0
  19. package/.agent/skills/frontend-testing/references/checklist.md +188 -0
  20. package/.agent/skills/frontend-testing/references/common-patterns.md +449 -0
  21. package/.agent/skills/frontend-testing/references/mocking.md +289 -0
  22. package/.agent/skills/frontend-testing/references/workflow.md +265 -0
  23. package/.agent/skills/prd-creator/JSON.md +613 -0
  24. package/.agent/skills/prd-creator/PRD.md +196 -0
  25. package/.agent/skills/prd-creator/SKILL.md +143 -0
  26. package/.agent/skills/skill-creator/SKILL.md +355 -0
  27. package/.agent/skills/skill-creator/references/output-patterns.md +86 -0
  28. package/.agent/skills/skill-creator/references/workflows.md +28 -0
  29. package/.agent/skills/skill-creator/scripts/init_skill.py +300 -0
  30. package/.agent/skills/skill-creator/scripts/package_skill.py +110 -0
  31. package/.agent/skills/vercel-react-best-practices/AGENTS.md +2249 -0
  32. package/.agent/skills/vercel-react-best-practices/SKILL.md +125 -0
  33. package/.agent/skills/vercel-react-best-practices/rules/advanced-event-handler-refs.md +55 -0
  34. package/.agent/skills/vercel-react-best-practices/rules/advanced-use-latest.md +49 -0
  35. package/.agent/skills/vercel-react-best-practices/rules/async-api-routes.md +38 -0
  36. package/.agent/skills/vercel-react-best-practices/rules/async-defer-await.md +80 -0
  37. package/.agent/skills/vercel-react-best-practices/rules/async-dependencies.md +36 -0
  38. package/.agent/skills/vercel-react-best-practices/rules/async-parallel.md +28 -0
  39. package/.agent/skills/vercel-react-best-practices/rules/async-suspense-boundaries.md +99 -0
  40. package/.agent/skills/vercel-react-best-practices/rules/bundle-barrel-imports.md +59 -0
  41. package/.agent/skills/vercel-react-best-practices/rules/bundle-conditional.md +31 -0
  42. package/.agent/skills/vercel-react-best-practices/rules/bundle-defer-third-party.md +49 -0
  43. package/.agent/skills/vercel-react-best-practices/rules/bundle-dynamic-imports.md +35 -0
  44. package/.agent/skills/vercel-react-best-practices/rules/bundle-preload.md +50 -0
  45. package/.agent/skills/vercel-react-best-practices/rules/client-event-listeners.md +74 -0
  46. package/.agent/skills/vercel-react-best-practices/rules/client-swr-dedup.md +56 -0
  47. package/.agent/skills/vercel-react-best-practices/rules/js-batch-dom-css.md +82 -0
  48. package/.agent/skills/vercel-react-best-practices/rules/js-cache-function-results.md +80 -0
  49. package/.agent/skills/vercel-react-best-practices/rules/js-cache-property-access.md +28 -0
  50. package/.agent/skills/vercel-react-best-practices/rules/js-cache-storage.md +70 -0
  51. package/.agent/skills/vercel-react-best-practices/rules/js-combine-iterations.md +32 -0
  52. package/.agent/skills/vercel-react-best-practices/rules/js-early-exit.md +50 -0
  53. package/.agent/skills/vercel-react-best-practices/rules/js-hoist-regexp.md +45 -0
  54. package/.agent/skills/vercel-react-best-practices/rules/js-index-maps.md +37 -0
  55. package/.agent/skills/vercel-react-best-practices/rules/js-length-check-first.md +49 -0
  56. package/.agent/skills/vercel-react-best-practices/rules/js-min-max-loop.md +82 -0
  57. package/.agent/skills/vercel-react-best-practices/rules/js-set-map-lookups.md +24 -0
  58. package/.agent/skills/vercel-react-best-practices/rules/js-tosorted-immutable.md +57 -0
  59. package/.agent/skills/vercel-react-best-practices/rules/rendering-activity.md +26 -0
  60. package/.agent/skills/vercel-react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
  61. package/.agent/skills/vercel-react-best-practices/rules/rendering-conditional-render.md +40 -0
  62. package/.agent/skills/vercel-react-best-practices/rules/rendering-content-visibility.md +38 -0
  63. package/.agent/skills/vercel-react-best-practices/rules/rendering-hoist-jsx.md +46 -0
  64. package/.agent/skills/vercel-react-best-practices/rules/rendering-hydration-no-flicker.md +82 -0
  65. package/.agent/skills/vercel-react-best-practices/rules/rendering-svg-precision.md +28 -0
  66. package/.agent/skills/vercel-react-best-practices/rules/rerender-defer-reads.md +39 -0
  67. package/.agent/skills/vercel-react-best-practices/rules/rerender-dependencies.md +45 -0
  68. package/.agent/skills/vercel-react-best-practices/rules/rerender-derived-state.md +29 -0
  69. package/.agent/skills/vercel-react-best-practices/rules/rerender-functional-setstate.md +74 -0
  70. package/.agent/skills/vercel-react-best-practices/rules/rerender-lazy-state-init.md +58 -0
  71. package/.agent/skills/vercel-react-best-practices/rules/rerender-memo.md +44 -0
  72. package/.agent/skills/vercel-react-best-practices/rules/rerender-transitions.md +40 -0
  73. package/.agent/skills/vercel-react-best-practices/rules/server-after-nonblocking.md +73 -0
  74. package/.agent/skills/vercel-react-best-practices/rules/server-cache-lru.md +41 -0
  75. package/.agent/skills/vercel-react-best-practices/rules/server-cache-react.md +26 -0
  76. package/.agent/skills/vercel-react-best-practices/rules/server-parallel-fetching.md +79 -0
  77. package/.agent/skills/vercel-react-best-practices/rules/server-serialization.md +38 -0
  78. package/.agent/skills/vitest-best-practices/AGENTS.md +84 -0
  79. package/.agent/skills/vitest-best-practices/SKILL.md +130 -0
  80. package/.agent/skills/vitest-best-practices/references/aaa-pattern.md +260 -0
  81. package/.agent/skills/vitest-best-practices/references/assertions.md +393 -0
  82. package/.agent/skills/vitest-best-practices/references/async-testing.md +454 -0
  83. package/.agent/skills/vitest-best-practices/references/error-handling.md +382 -0
  84. package/.agent/skills/vitest-best-practices/references/organization.md +212 -0
  85. package/.agent/skills/vitest-best-practices/references/parameterized-tests.md +297 -0
  86. package/.agent/skills/vitest-best-practices/references/performance.md +528 -0
  87. package/.agent/skills/vitest-best-practices/references/snapshot-testing.md +483 -0
  88. package/.agent/skills/vitest-best-practices/references/test-doubles.md +499 -0
  89. package/.agent/skills/vitest-best-practices/references/vitest-features.md +529 -0
  90. package/.agent/skills/web-design-guidelines/SKILL.md +39 -0
  91. package/.agent/tasks/.gitkeep +0 -0
  92. package/.agent/tasks.json +1 -0
  93. package/.claude/agents/code-reviewer.md +172 -0
  94. package/.claude/commands/aw.md +50 -0
  95. package/.claude/hooks/play-sound.js +87 -0
  96. package/.claude/hooks/pre-tool-use.js +40 -0
  97. package/.claude/settings.json +54 -0
  98. package/.claude/settings.local.json +13 -0
  99. package/.mcp.json +31 -0
  100. package/AGENTS.md +44 -0
  101. package/CLAUDE.md +1 -0
  102. package/README.md +236 -0
  103. package/bin/cli.js +156 -0
  104. package/bin/lib/copy.js +149 -0
  105. package/bin/lib/display.js +137 -0
  106. package/package.json +65 -0
  107. package/ralph.sh +333 -0
  108. package/scripts/lib/args.sh +44 -0
  109. package/scripts/lib/cleanup.sh +53 -0
  110. package/scripts/lib/constants.sh +25 -0
  111. package/scripts/lib/display.sh +196 -0
  112. package/scripts/lib/logging.sh +30 -0
  113. package/scripts/lib/notify.sh +41 -0
  114. package/scripts/lib/output.sh +147 -0
  115. package/scripts/lib/preflight.sh +57 -0
  116. package/scripts/lib/preview.sh +77 -0
  117. package/scripts/lib/promise.sh +76 -0
  118. package/scripts/lib/spinner.sh +85 -0
  119. package/scripts/lib/terminal.sh +57 -0
  120. package/scripts/lib/timing.sh +223 -0
@@ -0,0 +1,485 @@
1
+ # Complexity Reduction Patterns
2
+
3
+ This document provides patterns for reducing cognitive complexity in React components.
4
+
5
+ ## Understanding Complexity
6
+
7
+ ### What Increases Complexity
8
+
9
+ | Pattern | Complexity Impact |
10
+ | ------------------- | -------------------- |
11
+ | `if/else` | +1 per branch |
12
+ | Nested conditions | +1 per nesting level |
13
+ | `switch/case` | +1 per case |
14
+ | `for/while/do` | +1 per loop |
15
+ | `&&`/` | | ` chains | +1 per operator |
16
+ | Nested callbacks | +1 per nesting level |
17
+ | `try/catch` | +1 per catch |
18
+ | Ternary expressions | +1 per nesting |
19
+
20
+ ## Pattern 1: Replace Conditionals with Lookup Tables
21
+
22
+ **Before** (complexity: ~15):
23
+
24
+ ```typescript
25
+ const Template = useMemo(() => {
26
+ if (appDetail?.mode === AppModeEnum.CHAT) {
27
+ switch (locale) {
28
+ case LanguagesSupported[1]:
29
+ return <TemplateChatZh appDetail={appDetail} />
30
+ case LanguagesSupported[7]:
31
+ return <TemplateChatJa appDetail={appDetail} />
32
+ default:
33
+ return <TemplateChatEn appDetail={appDetail} />
34
+ }
35
+ }
36
+ if (appDetail?.mode === AppModeEnum.ADVANCED_CHAT) {
37
+ switch (locale) {
38
+ case LanguagesSupported[1]:
39
+ return <TemplateAdvancedChatZh appDetail={appDetail} />
40
+ case LanguagesSupported[7]:
41
+ return <TemplateAdvancedChatJa appDetail={appDetail} />
42
+ default:
43
+ return <TemplateAdvancedChatEn appDetail={appDetail} />
44
+ }
45
+ }
46
+ if (appDetail?.mode === AppModeEnum.WORKFLOW) {
47
+ // Similar pattern...
48
+ }
49
+ return null
50
+ }, [appDetail, locale])
51
+ ```
52
+
53
+ **After** (complexity: ~3):
54
+
55
+ ```typescript
56
+ // Define lookup table outside component
57
+ const TEMPLATE_MAP: Record<AppModeEnum, Record<string, FC<TemplateProps>>> = {
58
+ [AppModeEnum.CHAT]: {
59
+ [LanguagesSupported[1]]: TemplateChatZh,
60
+ [LanguagesSupported[7]]: TemplateChatJa,
61
+ default: TemplateChatEn,
62
+ },
63
+ [AppModeEnum.ADVANCED_CHAT]: {
64
+ [LanguagesSupported[1]]: TemplateAdvancedChatZh,
65
+ [LanguagesSupported[7]]: TemplateAdvancedChatJa,
66
+ default: TemplateAdvancedChatEn,
67
+ },
68
+ [AppModeEnum.WORKFLOW]: {
69
+ [LanguagesSupported[1]]: TemplateWorkflowZh,
70
+ [LanguagesSupported[7]]: TemplateWorkflowJa,
71
+ default: TemplateWorkflowEn,
72
+ },
73
+ // ...
74
+ }
75
+
76
+ // Clean component logic
77
+ const Template = useMemo(() => {
78
+ if (!appDetail?.mode) return null
79
+
80
+ const templates = TEMPLATE_MAP[appDetail.mode]
81
+ if (!templates) return null
82
+
83
+ const TemplateComponent = templates[locale] ?? templates.default
84
+ return <TemplateComponent appDetail={appDetail} />
85
+ }, [appDetail, locale])
86
+ ```
87
+
88
+ ## Pattern 2: Use Early Returns
89
+
90
+ **Before** (complexity: ~10):
91
+
92
+ ```typescript
93
+ const handleSubmit = () => {
94
+ if (isValid) {
95
+ if (hasChanges) {
96
+ if (isConnected) {
97
+ submitData()
98
+ } else {
99
+ showConnectionError()
100
+ }
101
+ } else {
102
+ showNoChangesMessage()
103
+ }
104
+ } else {
105
+ showValidationError()
106
+ }
107
+ }
108
+ ```
109
+
110
+ **After** (complexity: ~4):
111
+
112
+ ```typescript
113
+ const handleSubmit = () => {
114
+ if (!isValid) {
115
+ showValidationError()
116
+ return
117
+ }
118
+
119
+ if (!hasChanges) {
120
+ showNoChangesMessage()
121
+ return
122
+ }
123
+
124
+ if (!isConnected) {
125
+ showConnectionError()
126
+ return
127
+ }
128
+
129
+ submitData()
130
+ }
131
+ ```
132
+
133
+ ## Pattern 3: Extract Complex Conditions
134
+
135
+ **Before** (complexity: high):
136
+
137
+ ```typescript
138
+ const canPublish = (() => {
139
+ if (mode !== AppModeEnum.COMPLETION) {
140
+ if (!isAdvancedMode)
141
+ return true
142
+
143
+ if (modelModeType === ModelModeType.completion) {
144
+ if (!hasSetBlockStatus.history || !hasSetBlockStatus.query)
145
+ return false
146
+ return true
147
+ }
148
+ return true
149
+ }
150
+ return !promptEmpty
151
+ })()
152
+ ```
153
+
154
+ **After** (complexity: lower):
155
+
156
+ ```typescript
157
+ // Extract to named functions
158
+ const canPublishInCompletionMode = () => !promptEmpty
159
+
160
+ const canPublishInChatMode = () => {
161
+ if (!isAdvancedMode) return true
162
+ if (modelModeType !== ModelModeType.completion) return true
163
+ return hasSetBlockStatus.history && hasSetBlockStatus.query
164
+ }
165
+
166
+ // Clean main logic
167
+ const canPublish = mode === AppModeEnum.COMPLETION
168
+ ? canPublishInCompletionMode()
169
+ : canPublishInChatMode()
170
+ ```
171
+
172
+ ## Pattern 4: Replace Chained Ternaries
173
+
174
+ **Before** (complexity: ~5):
175
+
176
+ ```typescript
177
+ const statusText = serverActivated
178
+ ? t('status.running')
179
+ : serverPublished
180
+ ? t('status.inactive')
181
+ : appUnpublished
182
+ ? t('status.unpublished')
183
+ : t('status.notConfigured')
184
+ ```
185
+
186
+ **After** (complexity: ~2):
187
+
188
+ ```typescript
189
+ const getStatusText = () => {
190
+ if (serverActivated) return t('status.running')
191
+ if (serverPublished) return t('status.inactive')
192
+ if (appUnpublished) return t('status.unpublished')
193
+ return t('status.notConfigured')
194
+ }
195
+
196
+ const statusText = getStatusText()
197
+ ```
198
+
199
+ Or use lookup:
200
+
201
+ ```typescript
202
+ const STATUS_TEXT_MAP = {
203
+ running: 'status.running',
204
+ inactive: 'status.inactive',
205
+ unpublished: 'status.unpublished',
206
+ notConfigured: 'status.notConfigured',
207
+ } as const
208
+
209
+ const getStatusKey = (): keyof typeof STATUS_TEXT_MAP => {
210
+ if (serverActivated) return 'running'
211
+ if (serverPublished) return 'inactive'
212
+ if (appUnpublished) return 'unpublished'
213
+ return 'notConfigured'
214
+ }
215
+
216
+ const statusText = t(STATUS_TEXT_MAP[getStatusKey()])
217
+ ```
218
+
219
+ ## Pattern 5: Flatten Nested Loops
220
+
221
+ **Before** (complexity: high):
222
+
223
+ ```typescript
224
+ const processData = (items: Item[]) => {
225
+ const results: ProcessedItem[] = []
226
+
227
+ for (const item of items) {
228
+ if (item.isValid) {
229
+ for (const child of item.children) {
230
+ if (child.isActive) {
231
+ for (const prop of child.properties) {
232
+ if (prop.value !== null) {
233
+ results.push({
234
+ itemId: item.id,
235
+ childId: child.id,
236
+ propValue: prop.value,
237
+ })
238
+ }
239
+ }
240
+ }
241
+ }
242
+ }
243
+ }
244
+
245
+ return results
246
+ }
247
+ ```
248
+
249
+ **After** (complexity: lower):
250
+
251
+ ```typescript
252
+ // Use functional approach
253
+ const processData = (items: Item[]) => {
254
+ return items
255
+ .filter(item => item.isValid)
256
+ .flatMap(item =>
257
+ item.children
258
+ .filter(child => child.isActive)
259
+ .flatMap(child =>
260
+ child.properties
261
+ .filter(prop => prop.value !== null)
262
+ .map(prop => ({
263
+ itemId: item.id,
264
+ childId: child.id,
265
+ propValue: prop.value,
266
+ }))
267
+ )
268
+ )
269
+ }
270
+ ```
271
+
272
+ ## Pattern 6: Extract Event Handler Logic
273
+
274
+ **Before** (complexity: high in component):
275
+
276
+ ```typescript
277
+ const Component = () => {
278
+ const handleSelect = (data: DataSet[]) => {
279
+ if (isEqual(data.map(item => item.id), dataSets.map(item => item.id))) {
280
+ hideSelectDataSet()
281
+ return
282
+ }
283
+
284
+ formattingChangedDispatcher()
285
+ let newDatasets = data
286
+ if (data.find(item => !item.name)) {
287
+ const newSelected = produce(data, (draft) => {
288
+ data.forEach((item, index) => {
289
+ if (!item.name) {
290
+ const newItem = dataSets.find(i => i.id === item.id)
291
+ if (newItem)
292
+ draft[index] = newItem
293
+ }
294
+ })
295
+ })
296
+ setDataSets(newSelected)
297
+ newDatasets = newSelected
298
+ }
299
+ else {
300
+ setDataSets(data)
301
+ }
302
+ hideSelectDataSet()
303
+
304
+ // 40 more lines of logic...
305
+ }
306
+
307
+ return <div>...</div>
308
+ }
309
+ ```
310
+
311
+ **After** (complexity: lower):
312
+
313
+ ```typescript
314
+ // Extract to hook or utility
315
+ const useDatasetSelection = (dataSets: DataSet[], setDataSets: SetState<DataSet[]>) => {
316
+ const normalizeSelection = (data: DataSet[]) => {
317
+ const hasUnloadedItem = data.some(item => !item.name)
318
+ if (!hasUnloadedItem) return data
319
+
320
+ return produce(data, (draft) => {
321
+ data.forEach((item, index) => {
322
+ if (!item.name) {
323
+ const existing = dataSets.find(i => i.id === item.id)
324
+ if (existing) draft[index] = existing
325
+ }
326
+ })
327
+ })
328
+ }
329
+
330
+ const hasSelectionChanged = (newData: DataSet[]) => {
331
+ return !isEqual(
332
+ newData.map(item => item.id),
333
+ dataSets.map(item => item.id)
334
+ )
335
+ }
336
+
337
+ return { normalizeSelection, hasSelectionChanged }
338
+ }
339
+
340
+ // Component becomes cleaner
341
+ const Component = () => {
342
+ const { normalizeSelection, hasSelectionChanged } = useDatasetSelection(dataSets, setDataSets)
343
+
344
+ const handleSelect = (data: DataSet[]) => {
345
+ if (!hasSelectionChanged(data)) {
346
+ hideSelectDataSet()
347
+ return
348
+ }
349
+
350
+ formattingChangedDispatcher()
351
+ const normalized = normalizeSelection(data)
352
+ setDataSets(normalized)
353
+ hideSelectDataSet()
354
+ }
355
+
356
+ return <div>...</div>
357
+ }
358
+ ```
359
+
360
+ ## Pattern 7: Reduce Boolean Logic Complexity
361
+
362
+ **Before** (complexity: ~8):
363
+
364
+ ```typescript
365
+ const toggleDisabled = hasInsufficientPermissions
366
+ || appUnpublished
367
+ || missingStartNode
368
+ || triggerModeDisabled
369
+ || (isAdvancedApp && !currentWorkflow?.graph)
370
+ || (isBasicApp && !basicAppConfig.updated_at)
371
+ ```
372
+
373
+ **After** (complexity: ~3):
374
+
375
+ ```typescript
376
+ // Extract meaningful boolean functions
377
+ const isAppReady = () => {
378
+ if (isAdvancedApp) return !!currentWorkflow?.graph
379
+ return !!basicAppConfig.updated_at
380
+ }
381
+
382
+ const hasRequiredPermissions = () => {
383
+ return isCurrentWorkspaceEditor && !hasInsufficientPermissions
384
+ }
385
+
386
+ const canToggle = () => {
387
+ if (!hasRequiredPermissions()) return false
388
+ if (!isAppReady()) return false
389
+ if (missingStartNode) return false
390
+ if (triggerModeDisabled) return false
391
+ return true
392
+ }
393
+
394
+ const toggleDisabled = !canToggle()
395
+ ```
396
+
397
+ ## Pattern 8: Simplify useMemo/useCallback Dependencies
398
+
399
+ **Before** (complexity: multiple recalculations):
400
+
401
+ ```typescript
402
+ const payload = useMemo(() => {
403
+ let parameters: Parameter[] = []
404
+ let outputParameters: OutputParameter[] = []
405
+
406
+ if (!published) {
407
+ parameters = (inputs || []).map((item) => ({
408
+ name: item.variable,
409
+ description: '',
410
+ form: 'llm',
411
+ required: item.required,
412
+ type: item.type,
413
+ }))
414
+ outputParameters = (outputs || []).map((item) => ({
415
+ name: item.variable,
416
+ description: '',
417
+ type: item.value_type,
418
+ }))
419
+ }
420
+ else if (detail && detail.tool) {
421
+ parameters = (inputs || []).map((item) => ({
422
+ // Complex transformation...
423
+ }))
424
+ outputParameters = (outputs || []).map((item) => ({
425
+ // Complex transformation...
426
+ }))
427
+ }
428
+
429
+ return {
430
+ icon: detail?.icon || icon,
431
+ label: detail?.label || name,
432
+ // ...more fields
433
+ }
434
+ }, [detail, published, workflowAppId, icon, name, description, inputs, outputs])
435
+ ```
436
+
437
+ **After** (complexity: separated concerns):
438
+
439
+ ```typescript
440
+ // Separate transformations
441
+ const useParameterTransform = (inputs: InputVar[], detail?: ToolDetail, published?: boolean) => {
442
+ return useMemo(() => {
443
+ if (!published) {
444
+ return inputs.map(item => ({
445
+ name: item.variable,
446
+ description: '',
447
+ form: 'llm',
448
+ required: item.required,
449
+ type: item.type,
450
+ }))
451
+ }
452
+
453
+ if (!detail?.tool) return []
454
+
455
+ return inputs.map(item => ({
456
+ name: item.variable,
457
+ required: item.required,
458
+ type: item.type === 'paragraph' ? 'string' : item.type,
459
+ description: detail.tool.parameters.find(p => p.name === item.variable)?.llm_description || '',
460
+ form: detail.tool.parameters.find(p => p.name === item.variable)?.form || 'llm',
461
+ }))
462
+ }, [inputs, detail, published])
463
+ }
464
+
465
+ // Component uses hook
466
+ const parameters = useParameterTransform(inputs, detail, published)
467
+ const outputParameters = useOutputTransform(outputs, detail, published)
468
+
469
+ const payload = useMemo(() => ({
470
+ icon: detail?.icon || icon,
471
+ label: detail?.label || name,
472
+ parameters,
473
+ outputParameters,
474
+ // ...
475
+ }), [detail, icon, name, parameters, outputParameters])
476
+ ```
477
+
478
+ ## Target Metrics After Refactoring
479
+
480
+ | Metric | Target |
481
+ | ------------------ | -------------- |
482
+ | Total Complexity | Low complexity |
483
+ | Function Length | 30-100 lines |
484
+ | Nesting Depth | ≤ 3 levels |
485
+ | Conditional Chains | ≤ 3 conditions |