@vibe-forge/client 0.3.0 → 0.4.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 (158) hide show
  1. package/cli.cjs +1 -1
  2. package/dist/assets/{arc-CwMXUVsq.js → arc-DgIxeTMg.js} +1 -1
  3. package/dist/assets/{blockDiagram-c4efeb88-CGxJV7KJ.js → blockDiagram-c4efeb88-CEAob3X9.js} +1 -1
  4. package/dist/assets/{c4Diagram-c83219d4-BKhin7cY.js → c4Diagram-c83219d4-DwIxpDKd.js} +1 -1
  5. package/dist/assets/channel-DhtnrNJ6.js +1 -0
  6. package/dist/assets/{classDiagram-beda092f-BASmn22R.js → classDiagram-beda092f-Cz1q8u_0.js} +1 -1
  7. package/dist/assets/{classDiagram-v2-2358418a-BUk9rNBX.js → classDiagram-v2-2358418a-CImgTuwd.js} +1 -1
  8. package/dist/assets/clone-7bHB6YkC.js +1 -0
  9. package/dist/assets/{createText-1719965b-2XqnWjQY.js → createText-1719965b-C1_HJcCc.js} +1 -1
  10. package/dist/assets/devicon-BWlTeAUU.woff +0 -0
  11. package/dist/assets/devicon-CirD-cQx.ttf +0 -0
  12. package/dist/assets/devicon-Dg8iWy0i.svg +1211 -0
  13. package/dist/assets/devicon-TqfHp33-.eot +0 -0
  14. package/dist/assets/{edges-96097737-B7e32Jeg.js → edges-96097737-BU8qStzd.js} +1 -1
  15. package/dist/assets/{erDiagram-0228fc6a-CCR2or72.js → erDiagram-0228fc6a-DNA1Fz2L.js} +1 -1
  16. package/dist/assets/{flowDb-c6c81e3f-B72HWT9x.js → flowDb-c6c81e3f-DjiCStMN.js} +1 -1
  17. package/dist/assets/{flowDiagram-50d868cf-WOi0KARY.js → flowDiagram-50d868cf-CSDi0-RD.js} +1 -1
  18. package/dist/assets/flowDiagram-v2-4f6560a1-_13Sz5Wh.js +1 -0
  19. package/dist/assets/{flowchart-elk-definition-6af322e1-i_Yd0LCE.js → flowchart-elk-definition-6af322e1-DrhIMas7.js} +1 -1
  20. package/dist/assets/{ganttDiagram-a2739b55-CFH9zF14.js → ganttDiagram-a2739b55-CTZnUP5z.js} +1 -1
  21. package/dist/assets/{gitGraphDiagram-82fe8481-DglKfMze.js → gitGraphDiagram-82fe8481-COOW7jTi.js} +1 -1
  22. package/dist/assets/{graph-BKbBNGPf.js → graph-CIkpD4Kx.js} +1 -1
  23. package/dist/assets/{index-5325376f-BK7F9nSl.js → index-5325376f-aVVRRTIu.js} +1 -1
  24. package/dist/assets/index-D1giUI7r.css +1 -0
  25. package/dist/assets/index-DRSI_ZIL.js +514 -0
  26. package/dist/assets/{infoDiagram-8eee0895-BLFL77_D.js → infoDiagram-8eee0895-DQpZ1LVD.js} +1 -1
  27. package/dist/assets/{journeyDiagram-c64418c1-CS9XctDL.js → journeyDiagram-c64418c1-DoKguIuk.js} +1 -1
  28. package/dist/assets/{layout-By3JZZGt.js → layout-Tnmha8Nh.js} +1 -1
  29. package/dist/assets/{line-9GUsXbwv.js → line-BQR2SOyl.js} +1 -1
  30. package/dist/assets/{linear-DzGV4E9N.js → linear-DlG0eemV.js} +1 -1
  31. package/dist/assets/{mermaid.core-CG3Ib42Q.js → mermaid.core-BnwYO0He.js} +6 -6
  32. package/dist/assets/{mindmap-definition-8da855dc-WQ3LPKJU.js → mindmap-definition-8da855dc-BllYwDID.js} +1 -1
  33. package/dist/assets/{pieDiagram-a8764435-DHVIUZiN.js → pieDiagram-a8764435-DwCkhPVc.js} +1 -1
  34. package/dist/assets/{quadrantDiagram-1e28029f-C3G9Ye8-.js → quadrantDiagram-1e28029f-c40GKTU0.js} +1 -1
  35. package/dist/assets/{requirementDiagram-08caed73-C9ES1D5G.js → requirementDiagram-08caed73-DnQp2Tk6.js} +1 -1
  36. package/dist/assets/{sankeyDiagram-a04cb91d-B4BKXclQ.js → sankeyDiagram-a04cb91d-CnJrs13b.js} +1 -1
  37. package/dist/assets/{sequenceDiagram-c5b8d532-DrgEb25G.js → sequenceDiagram-c5b8d532-1YBwnpKu.js} +1 -1
  38. package/dist/assets/{stateDiagram-1ecb1508-CF1XWARJ.js → stateDiagram-1ecb1508-BFBxQ6Fh.js} +1 -1
  39. package/dist/assets/{stateDiagram-v2-c2b004d7-IO3i3yXv.js → stateDiagram-v2-c2b004d7-Dmechvv2.js} +1 -1
  40. package/dist/assets/{styles-b4e223ce-DACN9aSc.js → styles-b4e223ce-DWWfWX8O.js} +1 -1
  41. package/dist/assets/{styles-ca3715f6-bekm2WLP.js → styles-ca3715f6-CKKvZxaU.js} +1 -1
  42. package/dist/assets/{styles-d45a18b0-OzTDVBb8.js → styles-d45a18b0-dKMOUh9p.js} +1 -1
  43. package/dist/assets/{svgDrawCommon-b86b1483-BWroJerr.js → svgDrawCommon-b86b1483-CBgjChPM.js} +1 -1
  44. package/dist/assets/{timeline-definition-faaaa080-CCfRNigO.js → timeline-definition-faaaa080-NCt-HHmb.js} +1 -1
  45. package/dist/assets/{xychartDiagram-f5964ef8-C3cbfVqN.js → xychartDiagram-f5964ef8-BJhXS4dG.js} +1 -1
  46. package/dist/index.html +2 -7
  47. package/index.html +0 -5
  48. package/package.json +11 -6
  49. package/src/App.tsx +2 -0
  50. package/src/api/README.md +26 -0
  51. package/src/api/automation.ts +88 -0
  52. package/src/api/base.ts +54 -0
  53. package/src/api/benchmark.ts +45 -0
  54. package/src/api/config.ts +24 -0
  55. package/src/api/knowledge.ts +72 -0
  56. package/src/api/projects.ts +15 -0
  57. package/src/api/sessions.ts +82 -0
  58. package/src/api/types.ts +20 -0
  59. package/src/api.ts +44 -269
  60. package/src/components/AutomationView/AutomationView.scss +5 -1
  61. package/src/components/AutomationView/RuleFormPanel.tsx +3 -2
  62. package/src/components/AutomationView/TaskList.scss +4 -6
  63. package/src/components/AutomationView/TaskList.tsx +2 -1
  64. package/src/components/AutomationView/TriggerList.scss +4 -1
  65. package/src/components/BenchmarkView/BenchmarkCasePanel.scss +267 -0
  66. package/src/components/BenchmarkView/BenchmarkCasePanel.tsx +309 -0
  67. package/src/components/BenchmarkView/BenchmarkSidebar.scss +182 -0
  68. package/src/components/BenchmarkView/BenchmarkSidebar.tsx +262 -0
  69. package/src/components/BenchmarkView/BenchmarkView.scss +78 -0
  70. package/src/components/BenchmarkView/index.tsx +197 -0
  71. package/src/components/BenchmarkView/types.ts +10 -0
  72. package/src/components/BenchmarkView/utils.ts +21 -0
  73. package/src/components/Chat.tsx +37 -29
  74. package/src/components/{chat/CodeBlock.tsx → CodeBlock.tsx} +3 -1
  75. package/src/components/ConfigView.tsx +7 -0
  76. package/src/components/{chat/MarkdownContent.tsx → MarkdownContent.tsx} +1 -1
  77. package/src/components/NavRail.tsx +7 -0
  78. package/src/components/chat/ChatHeader.scss +37 -19
  79. package/src/components/chat/ChatHeader.tsx +6 -9
  80. package/src/components/chat/ChatHistoryView.tsx +89 -45
  81. package/src/components/chat/CurrentTodoList.tsx +10 -9
  82. package/src/components/chat/{MessageItem.scss → Messages/MessageItem.scss} +14 -0
  83. package/src/components/chat/{MessageItem.tsx → Messages/MessageItem.tsx} +30 -8
  84. package/src/components/chat/{messageUtils.ts → Messages/message-utils.ts} +1 -1
  85. package/src/components/chat/{Sender.scss → Sender/Sender.scss} +80 -0
  86. package/src/components/chat/{Sender.tsx → Sender/Sender.tsx} +161 -5
  87. package/src/components/chat/tools/DefaultTool.tsx +184 -21
  88. package/src/components/chat/tools/adapter-claude/BashTool.scss +67 -51
  89. package/src/components/chat/tools/adapter-claude/BashTool.tsx +83 -49
  90. package/src/components/chat/tools/adapter-claude/GlobTool.scss +0 -79
  91. package/src/components/chat/tools/adapter-claude/GlobTool.tsx +16 -36
  92. package/src/components/chat/tools/adapter-claude/GrepTool.scss +0 -87
  93. package/src/components/chat/tools/adapter-claude/GrepTool.tsx +22 -41
  94. package/src/components/chat/tools/adapter-claude/LSTool.scss +0 -79
  95. package/src/components/chat/tools/adapter-claude/LSTool.tsx +15 -15
  96. package/src/components/chat/tools/adapter-claude/ReadTool.scss +0 -55
  97. package/src/components/chat/tools/adapter-claude/ReadTool.tsx +20 -42
  98. package/src/components/chat/tools/adapter-claude/TodoTool.scss +8 -23
  99. package/src/components/chat/tools/adapter-claude/TodoTool.tsx +24 -11
  100. package/src/components/chat/tools/adapter-claude/WriteTool.scss +21 -69
  101. package/src/components/chat/tools/adapter-claude/WriteTool.tsx +22 -58
  102. package/src/components/chat/tools/adapter-claude/index.ts +4 -10
  103. package/src/components/chat/tools/adapter-claude/utils.ts +54 -0
  104. package/src/components/chat/tools/core/ToolCallBox.scss +356 -0
  105. package/src/components/chat/{ToolGroup.tsx → tools/core/ToolGroup.tsx} +26 -7
  106. package/src/components/chat/{ToolRenderer.tsx → tools/core/ToolRenderer.tsx} +6 -4
  107. package/src/components/chat/tools/plugin-chrome-devtools/ChromeDevtoolsTool.scss +11 -0
  108. package/src/components/chat/tools/plugin-chrome-devtools/ChromeDevtoolsTool.tsx +75 -0
  109. package/src/components/chat/tools/plugin-chrome-devtools/index.ts +45 -0
  110. package/src/components/chat/tools/task/GetTaskInfoTool.scss +2 -27
  111. package/src/components/chat/tools/task/GetTaskInfoTool.tsx +48 -38
  112. package/src/components/chat/tools/task/ListTasksTool.scss +3 -28
  113. package/src/components/chat/tools/task/ListTasksTool.tsx +11 -8
  114. package/src/components/chat/tools/task/StartTasksTool.scss +3 -28
  115. package/src/components/chat/tools/task/StartTasksTool.tsx +14 -17
  116. package/src/components/chat/tools/task/components/TaskRow.scss +105 -0
  117. package/src/components/chat/tools/task/components/TaskRow.tsx +163 -0
  118. package/src/components/chat/tools/task/components/TaskToolCard.scss +15 -15
  119. package/src/components/chat/tools/task/components/TaskToolCard.tsx +8 -6
  120. package/src/components/config/ConfigSectionForm.tsx +12 -1
  121. package/src/components/config/channelDefinitions.ts +6 -0
  122. package/src/components/config/configSchema.ts +10 -1
  123. package/src/components/config/recordEditors/ChannelRecordEditor.scss +1 -0
  124. package/src/components/config/recordEditors/ChannelRecordEditor.tsx +397 -0
  125. package/src/components/config/recordEditors/index.tsx +1 -0
  126. package/src/components/knowledge-base/components/RuleItem.tsx +1 -1
  127. package/src/components/knowledge-base/components/SpecItem.tsx +1 -1
  128. package/src/hooks/chat/use-chat-interaction.ts +26 -0
  129. package/src/{components/chat/useChatModels.tsx → hooks/chat/use-chat-models.tsx} +46 -15
  130. package/src/hooks/chat/use-chat-permission-mode.ts +47 -0
  131. package/src/hooks/chat/use-chat-scroll.ts +51 -0
  132. package/src/hooks/chat/use-chat-session-actions.ts +147 -0
  133. package/src/hooks/chat/use-chat-session-messages.ts +250 -0
  134. package/src/hooks/chat/use-chat-session.ts +57 -0
  135. package/src/hooks/chat/use-chat-view.ts +39 -0
  136. package/src/main.tsx +10 -13
  137. package/src/resources/locales/en.json +66 -0
  138. package/src/resources/locales/zh.json +66 -0
  139. package/src/runtime-config.ts +52 -0
  140. package/src/vite-env.d.ts +11 -0
  141. package/src/ws.ts +5 -3
  142. package/vite.config.ts +12 -4
  143. package/dist/assets/channel-jbCEHqbG.js +0 -1
  144. package/dist/assets/clone-CCRKqS4L.js +0 -1
  145. package/dist/assets/flowDiagram-v2-4f6560a1-Baslbgn4.js +0 -1
  146. package/dist/assets/index-B0qfCb1G.css +0 -1
  147. package/dist/assets/index-CNo75dYr.js +0 -497
  148. package/src/components/chat/ToolCallBox.scss +0 -137
  149. package/src/components/chat/useChatSession.ts +0 -370
  150. /package/src/components/{chat/CodeBlock.scss → CodeBlock.scss} +0 -0
  151. /package/src/components/chat/{MessageFooter.tsx → Messages/MessageFooter.tsx} +0 -0
  152. /package/src/components/chat/{CompletionMenu.scss → Sender/CompletionMenu.scss} +0 -0
  153. /package/src/components/chat/{CompletionMenu.tsx → Sender/CompletionMenu.tsx} +0 -0
  154. /package/src/components/chat/{ThinkingStatus.scss → Sender/ThinkingStatus.scss} +0 -0
  155. /package/src/components/chat/{ThinkingStatus.tsx → Sender/ThinkingStatus.tsx} +0 -0
  156. /package/src/components/chat/{ToolCallBox.tsx → tools/core/ToolCallBox.tsx} +0 -0
  157. /package/src/components/chat/{ToolGroup.scss → tools/core/ToolGroup.scss} +0 -0
  158. /package/src/{components/chat/safeSerialize.ts → utils/safe-serialize.ts} +0 -0
@@ -0,0 +1,163 @@
1
+ import './TaskRow.scss'
2
+
3
+ import React, { useEffect, useMemo, useRef, useState } from 'react'
4
+ import { useNavigate } from 'react-router-dom'
5
+
6
+ import type { ChatMessage, WSEvent } from '@vibe-forge/core'
7
+
8
+ import { connectionManager } from '#~/connectionManager.js'
9
+ import { MarkdownContent } from '#~/components/MarkdownContent'
10
+
11
+ export interface TaskRowProps {
12
+ description?: string
13
+ status?: 'running' | 'completed' | 'failed'
14
+ logs?: string[] | null
15
+ sessionId?: string | null
16
+ titleFallback?: string
17
+ metaChips?: Array<string | null | undefined>
18
+ showExecutionIcon?: boolean
19
+ background?: boolean
20
+ foregroundLabel?: string
21
+ backgroundLabel?: string
22
+ }
23
+
24
+ function parseTaskDescription(description?: string): { title: string } {
25
+ if (!description) {
26
+ return { title: '' }
27
+ }
28
+ const lines = description.split('\n')
29
+ const title = lines[0] || ''
30
+ return { title }
31
+ }
32
+
33
+ function getStatusIcon(status?: string): string {
34
+ switch (status) {
35
+ case 'running':
36
+ return 'play_circle'
37
+ case 'completed':
38
+ return 'check_circle'
39
+ case 'failed':
40
+ return 'error'
41
+ default:
42
+ return 'help_outline'
43
+ }
44
+ }
45
+
46
+ export function TaskRow({
47
+ description,
48
+ status,
49
+ logs,
50
+ sessionId,
51
+ titleFallback,
52
+ metaChips,
53
+ showExecutionIcon,
54
+ background,
55
+ foregroundLabel,
56
+ backgroundLabel
57
+ }: TaskRowProps) {
58
+ const navigate = useNavigate()
59
+ const [liveLogs, setLiveLogs] = useState<string[]>(logs ?? [])
60
+ const [liveStatus, setLiveStatus] = useState(status)
61
+ const seenMessageIdsRef = useRef<Set<string>>(new Set())
62
+ const { title } = parseTaskDescription(description)
63
+ const resolvedTitle = title || titleFallback || ''
64
+ const chips = (metaChips ?? []).filter((item): item is string => Boolean(item))
65
+ const isForeground = background === false
66
+ const executionClass = isForeground
67
+ ? 'task-row__execution-icon--foreground'
68
+ : 'task-row__execution-icon--background'
69
+ const executionLabel = isForeground ? foregroundLabel : backgroundLabel
70
+ const displaySessionId = sessionId != null && sessionId !== ''
71
+ const logText = useMemo(() => (liveLogs?.join('\n') ?? '').trim(), [liveLogs])
72
+
73
+ useEffect(() => {
74
+ setLiveLogs(logs ?? [])
75
+ }, [logs])
76
+
77
+ useEffect(() => {
78
+ setLiveStatus(status)
79
+ }, [status])
80
+
81
+ useEffect(() => {
82
+ if (!sessionId) return
83
+ const cleanup = connectionManager.connect(sessionId, {
84
+ onMessage(data: WSEvent) {
85
+ if (data.type === 'message') {
86
+ const message = data.message as ChatMessage
87
+ if (message.id && seenMessageIdsRef.current.has(message.id)) {
88
+ return
89
+ }
90
+ if (message.id) {
91
+ seenMessageIdsRef.current.add(message.id)
92
+ }
93
+ const text = extractMessageText(message)
94
+ if (text !== '') {
95
+ setLiveLogs((prev) => [...prev, text])
96
+ }
97
+ } else if (data.type === 'session_updated' && data.session?.id === sessionId) {
98
+ const updatedStatus = data.session?.status as typeof status | undefined
99
+ if (updatedStatus) {
100
+ setLiveStatus(updatedStatus)
101
+ }
102
+ }
103
+ }
104
+ })
105
+ return () => {
106
+ cleanup?.()
107
+ }
108
+ }, [sessionId])
109
+
110
+ return (
111
+ <div className='task-row'>
112
+ <div className='task-row__header'>
113
+ <div className='task-row__left'>
114
+ <span className={`material-symbols-rounded task-row__status-icon ${liveStatus ?? 'help_outline'}`}>
115
+ {getStatusIcon(liveStatus)}
116
+ </span>
117
+ {showExecutionIcon && (
118
+ <span
119
+ className={`material-symbols-rounded task-row__execution-icon ${executionClass}`}
120
+ title={executionLabel}
121
+ >
122
+ {isForeground ? 'desktop_windows' : 'schedule'}
123
+ </span>
124
+ )}
125
+ </div>
126
+ <span className='task-row__title'>{resolvedTitle}</span>
127
+ {displaySessionId && (
128
+ <button
129
+ type='button'
130
+ className='task-row__session-link'
131
+ onClick={() => navigate(`/session/${sessionId}`)}
132
+ >
133
+ {sessionId}
134
+ </button>
135
+ )}
136
+ {chips.length > 0 && (
137
+ <div className='task-row__meta'>
138
+ {chips.map((item) => (
139
+ <span className='task-row__meta-chip' key={item}>{item}</span>
140
+ ))}
141
+ </div>
142
+ )}
143
+ </div>
144
+ {logText !== '' && (
145
+ <div className='task-row__logs'>
146
+ <MarkdownContent content={logText} />
147
+ </div>
148
+ )}
149
+ </div>
150
+ )
151
+ }
152
+
153
+ function extractMessageText(message: ChatMessage): string {
154
+ if (typeof message.content === 'string') {
155
+ return message.content
156
+ }
157
+ if (Array.isArray(message.content)) {
158
+ return message.content
159
+ .map((c) => (c.type === 'text' ? c.text : ''))
160
+ .join('')
161
+ }
162
+ return ''
163
+ }
@@ -1,8 +1,8 @@
1
1
  .task-tool-card {
2
2
  display: grid;
3
- grid-template-columns: 24px minmax(0, 1fr);
4
- gap: 12px;
5
- padding: 12px;
3
+ grid-template-columns: 20px minmax(0, 1fr);
4
+ gap: 10px;
5
+ padding: 10px;
6
6
  border: 1px solid var(--border-color);
7
7
  border-radius: 8px;
8
8
  background: color-mix(
@@ -14,12 +14,12 @@
14
14
  &__left {
15
15
  display: flex;
16
16
  flex-direction: column;
17
- gap: 8px;
17
+ gap: 6px;
18
18
  align-items: center;
19
19
  }
20
20
 
21
21
  &__status-icon {
22
- font-size: 20px;
22
+ font-size: 18px;
23
23
  color: var(--sub-text-color);
24
24
  transition: color .2s ease;
25
25
 
@@ -41,7 +41,7 @@
41
41
  }
42
42
 
43
43
  &__execution-icon {
44
- font-size: 20px;
44
+ font-size: 18px;
45
45
  color: var(--sub-text-color);
46
46
  transition: color .2s ease;
47
47
 
@@ -69,15 +69,15 @@
69
69
  display: flex;
70
70
  justify-content: space-between;
71
71
  align-items: flex-start;
72
- margin-bottom: 6px;
72
+ margin-bottom: 4px;
73
73
  }
74
74
 
75
75
  &__title {
76
- font-size: 14px;
76
+ font-size: 13px;
77
77
  font-weight: 600;
78
78
  color: var(--text-color);
79
79
  flex: 1;
80
- margin-right: 12px;
80
+ margin-right: 8px;
81
81
  }
82
82
 
83
83
  &__session-id {
@@ -103,24 +103,24 @@
103
103
  }
104
104
 
105
105
  &__content {
106
- font-size: 13px;
106
+ font-size: 12px;
107
107
  line-height: 1.5;
108
108
  color: var(--text-color);
109
- margin-bottom: 8px;
109
+ margin-bottom: 6px;
110
110
  }
111
111
 
112
112
  &__meta {
113
- margin: 6px 0;
113
+ margin: 4px 0;
114
114
  display: flex;
115
115
  flex-wrap: wrap;
116
- gap: 6px;
116
+ gap: 4px;
117
117
  }
118
118
 
119
119
  &__meta-chip {
120
- padding: 2px 6px;
120
+ padding: 1px 6px;
121
121
  border: 1px solid var(--border-color);
122
122
  border-radius: 999px;
123
- font-size: 11px;
123
+ font-size: 10px;
124
124
  color: var(--sub-text-color);
125
125
  background: var(--bg-color);
126
126
  }
@@ -6,7 +6,7 @@ import { useNavigate } from 'react-router-dom'
6
6
  import type { ChatMessage, WSEvent } from '@vibe-forge/core'
7
7
 
8
8
  import { connectionManager } from '#~/connectionManager.js'
9
- import { CodeBlock } from '../../../CodeBlock'
9
+ import { CodeBlock } from '#~/components/CodeBlock'
10
10
 
11
11
  export interface TaskToolCardProps {
12
12
  description?: string
@@ -154,11 +154,13 @@ export function TaskToolCard({
154
154
  ))}
155
155
  </div>
156
156
  )}
157
- <CodeBlock
158
- hideHeader
159
- code={logText}
160
- lang='md'
161
- />
157
+ {logText !== '' && (
158
+ <CodeBlock
159
+ hideHeader
160
+ code={logText}
161
+ lang='md'
162
+ />
163
+ )}
162
164
  </div>
163
165
  </div>
164
166
  )
@@ -20,6 +20,7 @@ import {
20
20
  import type { TranslationFn } from './configUtils'
21
21
  import {
22
22
  BooleanRecordEditor,
23
+ ChannelRecordEditor,
23
24
  KeyValueEditor,
24
25
  McpServersRecordEditor,
25
26
  ModelServicesRecordEditor,
@@ -49,7 +50,7 @@ export const SectionForm = ({
49
50
  if (fields.length === 0) {
50
51
  return <Empty description={t('common.noData')} image={null} />
51
52
  }
52
- const directRecordSections = new Set(['modelServices', 'adapters', 'plugins', 'mcp'])
53
+ const directRecordSections = new Set(['modelServices', 'channels', 'adapters', 'plugins', 'mcp'])
53
54
 
54
55
  const modelServiceEntries = Object.entries(mergedModelServices)
55
56
  const modelServiceOptions: Array<{ value: string; label: ReactNode }> = modelServiceEntries.map(([key, entry]) => {
@@ -97,6 +98,7 @@ export const SectionForm = ({
97
98
 
98
99
  const getRecordKeyPlaceholder = (field: FieldSpec) => {
99
100
  if (sectionKey === 'modelServices') return t('config.editor.newModelServiceName')
101
+ if (sectionKey === 'channels') return t('config.editor.newChannelName')
100
102
  if (sectionKey === 'adapters') return t('config.editor.newAdapterName')
101
103
  if (sectionKey === 'plugins') {
102
104
  if (field.path.join('.') === 'extraKnownMarketplaces') return t('config.editor.newMarketplaceName')
@@ -247,6 +249,15 @@ export const SectionForm = ({
247
249
  keyPlaceholder={getRecordKeyPlaceholder(field)}
248
250
  />
249
251
  )
252
+ } else if (field.recordKind === 'channels') {
253
+ control = (
254
+ <ChannelRecordEditor
255
+ value={recordValue}
256
+ onChange={handleValueChange}
257
+ t={t}
258
+ keyPlaceholder={getRecordKeyPlaceholder(field)}
259
+ />
260
+ )
250
261
  } else if (field.recordKind === 'mcpServers') {
251
262
  control = (
252
263
  <McpServersRecordEditor
@@ -0,0 +1,6 @@
1
+ import { larkChannelDefinition } from '@vibe-forge/channel-lark'
2
+ import type { ChannelDescriptor } from '@vibe-forge/core/channel'
3
+
4
+ export const channelDefinitions: ChannelDescriptor[] = [
5
+ larkChannelDefinition
6
+ ]
@@ -9,7 +9,7 @@ export type FieldValueType =
9
9
  | 'record'
10
10
  | 'shortcut'
11
11
 
12
- export type RecordKind = 'json' | 'modelServices' | 'mcpServers' | 'boolean' | 'keyValue'
12
+ export type RecordKind = 'json' | 'modelServices' | 'mcpServers' | 'boolean' | 'keyValue' | 'channels'
13
13
 
14
14
  export interface FieldOption {
15
15
  value: string
@@ -260,6 +260,15 @@ export const configSchema: Record<string, FieldSpec[]> = {
260
260
  icon: 'hub'
261
261
  }
262
262
  ],
263
+ channels: [
264
+ {
265
+ path: [],
266
+ type: 'record',
267
+ recordKind: 'channels',
268
+ defaultValue: {},
269
+ icon: 'campaign'
270
+ }
271
+ ],
263
272
  adapters: [
264
273
  {
265
274
  path: [],
@@ -0,0 +1 @@
1
+ @use './RecordEditors.scss';