@vibe-forge/client 0.2.0-alpha.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 (184) hide show
  1. package/LICENSE +21 -0
  2. package/cli.cjs +6 -0
  3. package/index.html +27 -0
  4. package/package.json +42 -0
  5. package/src/App.tsx +174 -0
  6. package/src/api.ts +241 -0
  7. package/src/components/ArchiveView.scss +168 -0
  8. package/src/components/ArchiveView.tsx +299 -0
  9. package/src/components/AutomationView/AutomationView.scss +26 -0
  10. package/src/components/AutomationView/RuleFormPanel.scss +129 -0
  11. package/src/components/AutomationView/RuleFormPanel.tsx +257 -0
  12. package/src/components/AutomationView/RuleSidebar.scss +219 -0
  13. package/src/components/AutomationView/RuleSidebar.tsx +258 -0
  14. package/src/components/AutomationView/RunHistoryPanel.scss +286 -0
  15. package/src/components/AutomationView/RunHistoryPanel.tsx +320 -0
  16. package/src/components/AutomationView/TaskList.scss +128 -0
  17. package/src/components/AutomationView/TaskList.tsx +79 -0
  18. package/src/components/AutomationView/TriggerList.scss +153 -0
  19. package/src/components/AutomationView/TriggerList.tsx +217 -0
  20. package/src/components/AutomationView/index.tsx +228 -0
  21. package/src/components/AutomationView/types.ts +21 -0
  22. package/src/components/Chat.scss +89 -0
  23. package/src/components/Chat.tsx +92 -0
  24. package/src/components/ConfigView.scss +185 -0
  25. package/src/components/ConfigView.tsx +258 -0
  26. package/src/components/NavRail.scss +71 -0
  27. package/src/components/NavRail.tsx +188 -0
  28. package/src/components/Sidebar.scss +112 -0
  29. package/src/components/Sidebar.tsx +291 -0
  30. package/src/components/chat/ChatHeader.scss +401 -0
  31. package/src/components/chat/ChatHeader.tsx +342 -0
  32. package/src/components/chat/ChatHistoryView.tsx +122 -0
  33. package/src/components/chat/ChatSettingsView.tsx +22 -0
  34. package/src/components/chat/ChatTimelineView.scss +53 -0
  35. package/src/components/chat/ChatTimelineView.tsx +158 -0
  36. package/src/components/chat/CodeBlock.scss +87 -0
  37. package/src/components/chat/CodeBlock.tsx +179 -0
  38. package/src/components/chat/CompletionMenu.scss +70 -0
  39. package/src/components/chat/CompletionMenu.tsx +58 -0
  40. package/src/components/chat/CurrentTodoList.scss +217 -0
  41. package/src/components/chat/CurrentTodoList.tsx +103 -0
  42. package/src/components/chat/MarkdownContent.tsx +43 -0
  43. package/src/components/chat/MessageFooter.tsx +48 -0
  44. package/src/components/chat/MessageItem.scss +251 -0
  45. package/src/components/chat/MessageItem.tsx +78 -0
  46. package/src/components/chat/NewSessionGuide.scss +186 -0
  47. package/src/components/chat/NewSessionGuide.tsx +167 -0
  48. package/src/components/chat/Sender.scss +367 -0
  49. package/src/components/chat/Sender.tsx +541 -0
  50. package/src/components/chat/SessionTimelinePanel/EventList.scss +58 -0
  51. package/src/components/chat/SessionTimelinePanel/EventList.tsx +212 -0
  52. package/src/components/chat/SessionTimelinePanel/gantt.ts +177 -0
  53. package/src/components/chat/SessionTimelinePanel/git-graph.ts +518 -0
  54. package/src/components/chat/SessionTimelinePanel/index.scss +28 -0
  55. package/src/components/chat/SessionTimelinePanel/index.tsx +121 -0
  56. package/src/components/chat/SessionTimelinePanel/mermaid.ts +4 -0
  57. package/src/components/chat/SessionTimelinePanel/types.ts +64 -0
  58. package/src/components/chat/SessionTimelinePanel/utils.ts +20 -0
  59. package/src/components/chat/ThinkingStatus.scss +70 -0
  60. package/src/components/chat/ThinkingStatus.tsx +13 -0
  61. package/src/components/chat/ToolCallBox.scss +137 -0
  62. package/src/components/chat/ToolCallBox.tsx +55 -0
  63. package/src/components/chat/ToolGroup.scss +154 -0
  64. package/src/components/chat/ToolGroup.tsx +102 -0
  65. package/src/components/chat/ToolRenderer.tsx +45 -0
  66. package/src/components/chat/messageUtils.ts +171 -0
  67. package/src/components/chat/safeSerialize.ts +84 -0
  68. package/src/components/chat/tools/DefaultTool.tsx +63 -0
  69. package/src/components/chat/tools/adapter-claude/BashTool.scss +71 -0
  70. package/src/components/chat/tools/adapter-claude/BashTool.tsx +82 -0
  71. package/src/components/chat/tools/adapter-claude/GlobTool.scss +88 -0
  72. package/src/components/chat/tools/adapter-claude/GlobTool.tsx +85 -0
  73. package/src/components/chat/tools/adapter-claude/GrepTool.scss +96 -0
  74. package/src/components/chat/tools/adapter-claude/GrepTool.tsx +114 -0
  75. package/src/components/chat/tools/adapter-claude/LSTool.scss +85 -0
  76. package/src/components/chat/tools/adapter-claude/LSTool.tsx +94 -0
  77. package/src/components/chat/tools/adapter-claude/ReadTool.scss +57 -0
  78. package/src/components/chat/tools/adapter-claude/ReadTool.tsx +87 -0
  79. package/src/components/chat/tools/adapter-claude/TodoTool.scss +78 -0
  80. package/src/components/chat/tools/adapter-claude/TodoTool.tsx +60 -0
  81. package/src/components/chat/tools/adapter-claude/WriteTool.scss +92 -0
  82. package/src/components/chat/tools/adapter-claude/WriteTool.tsx +86 -0
  83. package/src/components/chat/tools/adapter-claude/components/FileList.scss +65 -0
  84. package/src/components/chat/tools/adapter-claude/components/FileList.tsx +185 -0
  85. package/src/components/chat/tools/adapter-claude/index.ts +28 -0
  86. package/src/components/chat/tools/defineToolRender.ts +28 -0
  87. package/src/components/chat/tools/task/GetTaskInfoTool.scss +50 -0
  88. package/src/components/chat/tools/task/GetTaskInfoTool.tsx +88 -0
  89. package/src/components/chat/tools/task/ListTasksTool.scss +56 -0
  90. package/src/components/chat/tools/task/ListTasksTool.tsx +83 -0
  91. package/src/components/chat/tools/task/StartTasksTool.scss +56 -0
  92. package/src/components/chat/tools/task/StartTasksTool.tsx +96 -0
  93. package/src/components/chat/tools/task/components/TaskToolCard.scss +127 -0
  94. package/src/components/chat/tools/task/components/TaskToolCard.tsx +177 -0
  95. package/src/components/chat/tools/task/index.ts +15 -0
  96. package/src/components/chat/useChatModels.tsx +206 -0
  97. package/src/components/chat/useChatSession.ts +370 -0
  98. package/src/components/config/ConfigAboutSection.scss +111 -0
  99. package/src/components/config/ConfigAboutSection.tsx +86 -0
  100. package/src/components/config/ConfigDisplayValue.scss +22 -0
  101. package/src/components/config/ConfigDisplayValue.tsx +62 -0
  102. package/src/components/config/ConfigEditors.scss +65 -0
  103. package/src/components/config/ConfigEditors.tsx +98 -0
  104. package/src/components/config/ConfigFieldRow.scss +97 -0
  105. package/src/components/config/ConfigFieldRow.tsx +36 -0
  106. package/src/components/config/ConfigSectionForm.scss +94 -0
  107. package/src/components/config/ConfigSectionForm.tsx +436 -0
  108. package/src/components/config/ConfigSectionPanel.tsx +67 -0
  109. package/src/components/config/ConfigShortcutInput.scss +11 -0
  110. package/src/components/config/ConfigShortcutInput.tsx +52 -0
  111. package/src/components/config/ConfigSourceSwitch.tsx +57 -0
  112. package/src/components/config/configSchema.ts +319 -0
  113. package/src/components/config/configUtils.ts +83 -0
  114. package/src/components/config/index.tsx +5 -0
  115. package/src/components/config/recordEditors/BooleanRecordEditor.scss +1 -0
  116. package/src/components/config/recordEditors/BooleanRecordEditor.tsx +75 -0
  117. package/src/components/config/recordEditors/KeyValueEditor.scss +1 -0
  118. package/src/components/config/recordEditors/KeyValueEditor.tsx +97 -0
  119. package/src/components/config/recordEditors/McpServersRecordEditor.scss +1 -0
  120. package/src/components/config/recordEditors/McpServersRecordEditor.tsx +258 -0
  121. package/src/components/config/recordEditors/ModelServicesRecordEditor.scss +1 -0
  122. package/src/components/config/recordEditors/ModelServicesRecordEditor.tsx +233 -0
  123. package/src/components/config/recordEditors/RecordEditors.scss +117 -0
  124. package/src/components/config/recordEditors/RecordJsonEditor.scss +1 -0
  125. package/src/components/config/recordEditors/RecordJsonEditor.tsx +113 -0
  126. package/src/components/config/recordEditors/index.tsx +5 -0
  127. package/src/components/knowledge-base/KnowledgeBaseView.scss +19 -0
  128. package/src/components/knowledge-base/KnowledgeBaseView.tsx +186 -0
  129. package/src/components/knowledge-base/components/ActionButton.scss +5 -0
  130. package/src/components/knowledge-base/components/ActionButton.tsx +9 -0
  131. package/src/components/knowledge-base/components/EmptyState.scss +19 -0
  132. package/src/components/knowledge-base/components/EmptyState.tsx +42 -0
  133. package/src/components/knowledge-base/components/EntitiesTab.scss +5 -0
  134. package/src/components/knowledge-base/components/EntitiesTab.tsx +80 -0
  135. package/src/components/knowledge-base/components/EntityItem.scss +82 -0
  136. package/src/components/knowledge-base/components/EntityItem.tsx +79 -0
  137. package/src/components/knowledge-base/components/EntityList.scss +5 -0
  138. package/src/components/knowledge-base/components/EntityList.tsx +70 -0
  139. package/src/components/knowledge-base/components/FilterBar.scss +21 -0
  140. package/src/components/knowledge-base/components/FilterBar.tsx +51 -0
  141. package/src/components/knowledge-base/components/FlowsTab.scss +5 -0
  142. package/src/components/knowledge-base/components/FlowsTab.tsx +80 -0
  143. package/src/components/knowledge-base/components/KnowledgeBaseHeader.scss +27 -0
  144. package/src/components/knowledge-base/components/KnowledgeBaseHeader.tsx +29 -0
  145. package/src/components/knowledge-base/components/KnowledgeList.scss +19 -0
  146. package/src/components/knowledge-base/components/KnowledgeList.tsx +19 -0
  147. package/src/components/knowledge-base/components/LoadingState.scss +5 -0
  148. package/src/components/knowledge-base/components/LoadingState.tsx +11 -0
  149. package/src/components/knowledge-base/components/MetaList.scss +19 -0
  150. package/src/components/knowledge-base/components/MetaList.tsx +18 -0
  151. package/src/components/knowledge-base/components/RulesTab.scss +5 -0
  152. package/src/components/knowledge-base/components/RulesTab.tsx +49 -0
  153. package/src/components/knowledge-base/components/SectionHeader.scss +22 -0
  154. package/src/components/knowledge-base/components/SectionHeader.tsx +21 -0
  155. package/src/components/knowledge-base/components/SkillsTab.scss +5 -0
  156. package/src/components/knowledge-base/components/SkillsTab.tsx +49 -0
  157. package/src/components/knowledge-base/components/SpecItem.scss +138 -0
  158. package/src/components/knowledge-base/components/SpecItem.tsx +131 -0
  159. package/src/components/knowledge-base/components/SpecList.scss +5 -0
  160. package/src/components/knowledge-base/components/SpecList.tsx +70 -0
  161. package/src/components/knowledge-base/components/TabContent.scss +8 -0
  162. package/src/components/knowledge-base/components/TabContent.tsx +17 -0
  163. package/src/components/knowledge-base/components/TabLabel.scss +10 -0
  164. package/src/components/knowledge-base/components/TabLabel.tsx +15 -0
  165. package/src/components/knowledge-base/index.tsx +1 -0
  166. package/src/components/sidebar/SessionItem.scss +256 -0
  167. package/src/components/sidebar/SessionItem.tsx +265 -0
  168. package/src/components/sidebar/SessionList.scss +92 -0
  169. package/src/components/sidebar/SessionList.tsx +166 -0
  170. package/src/components/sidebar/SidebarHeader.scss +79 -0
  171. package/src/components/sidebar/SidebarHeader.tsx +128 -0
  172. package/src/connectionManager.ts +172 -0
  173. package/src/hooks/useGlobalShortcut.ts +26 -0
  174. package/src/hooks/useQueryParams.ts +54 -0
  175. package/src/i18n.ts +22 -0
  176. package/src/main.tsx +41 -0
  177. package/src/resources/locales/en.json +765 -0
  178. package/src/resources/locales/zh.json +766 -0
  179. package/src/store/index.ts +23 -0
  180. package/src/styles/global.scss +100 -0
  181. package/src/utils/shortcutUtils.ts +88 -0
  182. package/src/vite-env.d.ts +12 -0
  183. package/src/ws.ts +33 -0
  184. package/vite.config.ts +26 -0
@@ -0,0 +1,319 @@
1
+ export type FieldValueType =
2
+ | 'string'
3
+ | 'number'
4
+ | 'boolean'
5
+ | 'string[]'
6
+ | 'select'
7
+ | 'json'
8
+ | 'multiline'
9
+ | 'record'
10
+ | 'shortcut'
11
+
12
+ export type RecordKind = 'json' | 'modelServices' | 'mcpServers' | 'boolean' | 'keyValue'
13
+
14
+ export interface FieldOption {
15
+ value: string
16
+ label: string
17
+ }
18
+
19
+ export interface FieldSpec {
20
+ path: string[]
21
+ type: FieldValueType
22
+ defaultValue: unknown
23
+ icon?: string
24
+ options?: FieldOption[]
25
+ placeholderKey?: string
26
+ labelKey?: string
27
+ descriptionKey?: string
28
+ group?: 'base' | 'permissions' | 'env' | 'items'
29
+ recordKind?: RecordKind
30
+ sensitive?: boolean
31
+ hidden?: boolean
32
+ collapse?: {
33
+ key: string
34
+ labelKey: string
35
+ descKey?: string
36
+ togglePath?: string[]
37
+ }
38
+ }
39
+
40
+ export const configGroupMeta: Record<string, Record<string, { labelKey: string }>> = {
41
+ general: {
42
+ items: {
43
+ labelKey: 'config.fields.general.notifications.label'
44
+ }
45
+ }
46
+ }
47
+
48
+ export const configSchema: Record<string, FieldSpec[]> = {
49
+ general: [
50
+ { path: ['baseDir'], type: 'string', defaultValue: '.ai', icon: 'folder', group: 'base' },
51
+ { path: ['defaultAdapter'], type: 'select', defaultValue: '', icon: 'settings_input_component', group: 'base' },
52
+ { path: ['defaultModelService'], type: 'select', defaultValue: '', icon: 'hub', group: 'base' },
53
+ { path: ['defaultModel'], type: 'select', defaultValue: '', icon: 'model_training', group: 'base' },
54
+ { path: ['recommendedModels'], type: 'json', defaultValue: [], icon: 'stars', group: 'base' },
55
+ {
56
+ path: ['interfaceLanguage'],
57
+ type: 'select',
58
+ defaultValue: '',
59
+ icon: 'language',
60
+ group: 'base',
61
+ options: [
62
+ { value: 'zh', label: 'config.options.language.zh' },
63
+ { value: 'en', label: 'config.options.language.en' }
64
+ ]
65
+ },
66
+ {
67
+ path: ['modelLanguage'],
68
+ type: 'select',
69
+ defaultValue: '',
70
+ icon: 'translate',
71
+ group: 'base',
72
+ options: [
73
+ { value: 'zh', label: 'config.options.language.zh' },
74
+ { value: 'en', label: 'config.options.language.en' }
75
+ ]
76
+ },
77
+ { path: ['announcements'], type: 'string[]', defaultValue: [], icon: 'campaign', group: 'base' },
78
+ { path: ['permissions', 'allow'], type: 'string[]', defaultValue: [], icon: 'check_circle', group: 'permissions' },
79
+ { path: ['permissions', 'deny'], type: 'string[]', defaultValue: [], icon: 'block', group: 'permissions' },
80
+ { path: ['permissions', 'ask'], type: 'string[]', defaultValue: [], icon: 'help', group: 'permissions' },
81
+ { path: ['env'], type: 'record', recordKind: 'keyValue', defaultValue: {}, icon: 'terminal', group: 'env' },
82
+ { path: ['notifications', 'disabled'], type: 'boolean', defaultValue: false, icon: 'notifications', group: 'items' },
83
+ { path: ['notifications', 'volume'], type: 'number', defaultValue: 100, icon: 'volume_down', group: 'items' },
84
+ {
85
+ path: ['notifications', 'events', 'completed', 'title'],
86
+ type: 'string',
87
+ defaultValue: '',
88
+ icon: 'title',
89
+ group: 'items',
90
+ collapse: {
91
+ key: 'notifications.events.completed',
92
+ labelKey: 'config.fields.general.notifications.events.completed.label',
93
+ descKey: 'config.fields.general.notifications.events.completed.desc',
94
+ togglePath: ['notifications', 'events', 'completed', 'disabled']
95
+ }
96
+ },
97
+ {
98
+ path: ['notifications', 'events', 'completed', 'description'],
99
+ type: 'multiline',
100
+ defaultValue: '',
101
+ icon: 'notes',
102
+ group: 'items',
103
+ collapse: {
104
+ key: 'notifications.events.completed',
105
+ labelKey: 'config.fields.general.notifications.events.completed.label',
106
+ descKey: 'config.fields.general.notifications.events.completed.desc',
107
+ togglePath: ['notifications', 'events', 'completed', 'disabled']
108
+ }
109
+ },
110
+ {
111
+ path: ['notifications', 'events', 'completed', 'sound'],
112
+ type: 'string',
113
+ defaultValue: '',
114
+ icon: 'volume_up',
115
+ group: 'items',
116
+ collapse: {
117
+ key: 'notifications.events.completed',
118
+ labelKey: 'config.fields.general.notifications.events.completed.label',
119
+ descKey: 'config.fields.general.notifications.events.completed.desc',
120
+ togglePath: ['notifications', 'events', 'completed', 'disabled']
121
+ }
122
+ },
123
+ {
124
+ path: ['notifications', 'events', 'failed', 'title'],
125
+ type: 'string',
126
+ defaultValue: '',
127
+ icon: 'title',
128
+ group: 'items',
129
+ collapse: {
130
+ key: 'notifications.events.failed',
131
+ labelKey: 'config.fields.general.notifications.events.failed.label',
132
+ descKey: 'config.fields.general.notifications.events.failed.desc',
133
+ togglePath: ['notifications', 'events', 'failed', 'disabled']
134
+ }
135
+ },
136
+ {
137
+ path: ['notifications', 'events', 'failed', 'description'],
138
+ type: 'multiline',
139
+ defaultValue: '',
140
+ icon: 'notes',
141
+ group: 'items',
142
+ collapse: {
143
+ key: 'notifications.events.failed',
144
+ labelKey: 'config.fields.general.notifications.events.failed.label',
145
+ descKey: 'config.fields.general.notifications.events.failed.desc',
146
+ togglePath: ['notifications', 'events', 'failed', 'disabled']
147
+ }
148
+ },
149
+ {
150
+ path: ['notifications', 'events', 'failed', 'sound'],
151
+ type: 'string',
152
+ defaultValue: '',
153
+ icon: 'volume_up',
154
+ group: 'items',
155
+ collapse: {
156
+ key: 'notifications.events.failed',
157
+ labelKey: 'config.fields.general.notifications.events.failed.label',
158
+ descKey: 'config.fields.general.notifications.events.failed.desc',
159
+ togglePath: ['notifications', 'events', 'failed', 'disabled']
160
+ }
161
+ },
162
+ {
163
+ path: ['notifications', 'events', 'terminated', 'title'],
164
+ type: 'string',
165
+ defaultValue: '',
166
+ icon: 'title',
167
+ group: 'items',
168
+ collapse: {
169
+ key: 'notifications.events.terminated',
170
+ labelKey: 'config.fields.general.notifications.events.terminated.label',
171
+ descKey: 'config.fields.general.notifications.events.terminated.desc',
172
+ togglePath: ['notifications', 'events', 'terminated', 'disabled']
173
+ }
174
+ },
175
+ {
176
+ path: ['notifications', 'events', 'terminated', 'description'],
177
+ type: 'multiline',
178
+ defaultValue: '',
179
+ icon: 'notes',
180
+ group: 'items',
181
+ collapse: {
182
+ key: 'notifications.events.terminated',
183
+ labelKey: 'config.fields.general.notifications.events.terminated.label',
184
+ descKey: 'config.fields.general.notifications.events.terminated.desc',
185
+ togglePath: ['notifications', 'events', 'terminated', 'disabled']
186
+ }
187
+ },
188
+ {
189
+ path: ['notifications', 'events', 'terminated', 'sound'],
190
+ type: 'string',
191
+ defaultValue: '',
192
+ icon: 'volume_up',
193
+ group: 'items',
194
+ collapse: {
195
+ key: 'notifications.events.terminated',
196
+ labelKey: 'config.fields.general.notifications.events.terminated.label',
197
+ descKey: 'config.fields.general.notifications.events.terminated.desc',
198
+ togglePath: ['notifications', 'events', 'terminated', 'disabled']
199
+ }
200
+ },
201
+ {
202
+ path: ['notifications', 'events', 'waiting_input', 'title'],
203
+ type: 'string',
204
+ defaultValue: '',
205
+ icon: 'title',
206
+ group: 'items',
207
+ collapse: {
208
+ key: 'notifications.events.waiting_input',
209
+ labelKey: 'config.fields.general.notifications.events.waiting_input.label',
210
+ descKey: 'config.fields.general.notifications.events.waiting_input.desc',
211
+ togglePath: ['notifications', 'events', 'waiting_input', 'disabled']
212
+ }
213
+ },
214
+ {
215
+ path: ['notifications', 'events', 'waiting_input', 'description'],
216
+ type: 'multiline',
217
+ defaultValue: '',
218
+ icon: 'notes',
219
+ group: 'items',
220
+ collapse: {
221
+ key: 'notifications.events.waiting_input',
222
+ labelKey: 'config.fields.general.notifications.events.waiting_input.label',
223
+ descKey: 'config.fields.general.notifications.events.waiting_input.desc',
224
+ togglePath: ['notifications', 'events', 'waiting_input', 'disabled']
225
+ }
226
+ },
227
+ {
228
+ path: ['notifications', 'events', 'waiting_input', 'sound'],
229
+ type: 'string',
230
+ defaultValue: '',
231
+ icon: 'volume_up',
232
+ group: 'items',
233
+ collapse: {
234
+ key: 'notifications.events.waiting_input',
235
+ labelKey: 'config.fields.general.notifications.events.waiting_input.label',
236
+ descKey: 'config.fields.general.notifications.events.waiting_input.desc',
237
+ togglePath: ['notifications', 'events', 'waiting_input', 'disabled']
238
+ }
239
+ }
240
+ ],
241
+ conversation: [
242
+ {
243
+ path: ['style'],
244
+ type: 'select',
245
+ defaultValue: 'friendly',
246
+ icon: 'forum',
247
+ options: [
248
+ { value: 'friendly', label: 'config.options.conversation.friendly' },
249
+ { value: 'programmatic', label: 'config.options.conversation.programmatic' }
250
+ ]
251
+ },
252
+ { path: ['customInstructions'], type: 'multiline', defaultValue: '', icon: 'description' }
253
+ ],
254
+ modelServices: [
255
+ {
256
+ path: [],
257
+ type: 'record',
258
+ recordKind: 'modelServices',
259
+ defaultValue: {},
260
+ icon: 'hub'
261
+ }
262
+ ],
263
+ adapters: [
264
+ {
265
+ path: [],
266
+ type: 'record',
267
+ recordKind: 'json',
268
+ defaultValue: {},
269
+ icon: 'settings_input_component'
270
+ }
271
+ ],
272
+ plugins: [
273
+ {
274
+ path: ['plugins'],
275
+ type: 'record',
276
+ recordKind: 'json',
277
+ defaultValue: {},
278
+ icon: 'extension'
279
+ },
280
+ {
281
+ path: ['enabledPlugins'],
282
+ type: 'record',
283
+ recordKind: 'boolean',
284
+ defaultValue: {},
285
+ group: 'base',
286
+ icon: 'toggle_on',
287
+ labelKey: 'config.fields.plugins.enabled.label',
288
+ descriptionKey: 'config.fields.plugins.enabled.desc'
289
+ },
290
+ {
291
+ path: ['extraKnownMarketplaces'],
292
+ type: 'record',
293
+ recordKind: 'json',
294
+ defaultValue: {},
295
+ group: 'base',
296
+ icon: 'storefront',
297
+ labelKey: 'config.fields.plugins.marketplaces.label',
298
+ descriptionKey: 'config.fields.plugins.marketplaces.desc'
299
+ }
300
+ ],
301
+ mcp: [
302
+ { path: ['defaultIncludeMcpServers'], type: 'string[]', defaultValue: [], group: 'base', icon: 'playlist_add' },
303
+ { path: ['defaultExcludeMcpServers'], type: 'string[]', defaultValue: [], group: 'base', icon: 'playlist_remove' },
304
+ { path: ['noDefaultVibeForgeMcpServer'], type: 'boolean', defaultValue: false, group: 'base', icon: 'block' },
305
+ {
306
+ path: ['mcpServers'],
307
+ type: 'record',
308
+ recordKind: 'mcpServers',
309
+ defaultValue: {},
310
+ icon: 'account_tree'
311
+ }
312
+ ],
313
+ shortcuts: [
314
+ { path: ['newSession'], type: 'shortcut', defaultValue: '', icon: 'add_comment' },
315
+ { path: ['openConfig'], type: 'shortcut', defaultValue: '', icon: 'settings' },
316
+ { path: ['sendMessage'], type: 'shortcut', defaultValue: '', icon: 'send' },
317
+ { path: ['clearInput'], type: 'shortcut', defaultValue: '', icon: 'clear' }
318
+ ]
319
+ }
@@ -0,0 +1,83 @@
1
+ export type EditorValueType = 'string' | 'number' | 'boolean' | 'object' | 'array'
2
+
3
+ export type TranslationFn = (key: string, options?: { defaultValue?: string }) => string
4
+
5
+ export const isEmptyValue = (value: unknown) => {
6
+ if (value == null) return true
7
+ if (Array.isArray(value)) return value.length === 0
8
+ if (typeof value === 'object') return Object.keys(value as Record<string, unknown>).length === 0
9
+ return false
10
+ }
11
+
12
+ export const cloneValue = (value: unknown) => {
13
+ if (value == null) return value
14
+ return JSON.parse(JSON.stringify(value)) as unknown
15
+ }
16
+
17
+ export const getValueType = (value: unknown): EditorValueType => {
18
+ if (Array.isArray(value)) return 'array'
19
+ if (value != null && typeof value === 'object') return 'object'
20
+ if (typeof value === 'number') return 'number'
21
+ if (typeof value === 'boolean') return 'boolean'
22
+ return 'string'
23
+ }
24
+
25
+ export const getTypeIcon = (valueType: EditorValueType) => {
26
+ if (valueType === 'string') return 'text_fields'
27
+ if (valueType === 'number') return 'numbers'
28
+ if (valueType === 'boolean') return 'toggle_on'
29
+ if (valueType === 'array') return 'view_list'
30
+ return 'account_tree'
31
+ }
32
+
33
+ export const getFieldLabel = (
34
+ t: TranslationFn,
35
+ sectionKey: string,
36
+ path: string[],
37
+ fallback: string
38
+ ) => {
39
+ if (path.length === 0) return fallback
40
+ const key = `config.fields.${sectionKey}.${path.join('.')}.label`
41
+ return t(key, { defaultValue: fallback })
42
+ }
43
+
44
+ export const getFieldDescription = (
45
+ t: TranslationFn,
46
+ sectionKey: string,
47
+ path: string[]
48
+ ) => {
49
+ if (path.length === 0) return ''
50
+ const key = `config.fields.${sectionKey}.${path.join('.')}.desc`
51
+ return t(key, { defaultValue: '' })
52
+ }
53
+
54
+ export const isSensitiveKey = (key: string) => /key|token|secret|password/i.test(key)
55
+
56
+ export const getValueByPath = (value: unknown, path: string[]) => {
57
+ if (path.length === 0) return value
58
+ let current = value
59
+ for (const key of path) {
60
+ if (current == null || typeof current !== 'object') return undefined
61
+ current = (current as Record<string, unknown>)[key]
62
+ }
63
+ return current
64
+ }
65
+
66
+ export const setValueByPath = (value: unknown, path: string[], nextValue: unknown) => {
67
+ if (path.length === 0) return nextValue
68
+ const root = (value != null && typeof value === 'object' && !Array.isArray(value))
69
+ ? { ...(value as Record<string, unknown>) }
70
+ : {}
71
+ let current: Record<string, unknown> = root
72
+ for (let index = 0; index < path.length - 1; index += 1) {
73
+ const key = path[index]
74
+ const existing = current[key]
75
+ const next = (existing != null && typeof existing === 'object' && !Array.isArray(existing))
76
+ ? { ...(existing as Record<string, unknown>) }
77
+ : {}
78
+ current[key] = next
79
+ current = next
80
+ }
81
+ current[path[path.length - 1]] = nextValue
82
+ return root
83
+ }
@@ -0,0 +1,5 @@
1
+ export { AboutSection } from './ConfigAboutSection'
2
+ export { DisplayValue } from './ConfigDisplayValue'
3
+ export { ConfigSectionPanel } from './ConfigSectionPanel'
4
+ export { ConfigSourceSwitch } from './ConfigSourceSwitch'
5
+ export { SectionForm } from './ConfigSectionForm'
@@ -0,0 +1 @@
1
+ @use './RecordEditors.scss';
@@ -0,0 +1,75 @@
1
+ import './BooleanRecordEditor.scss'
2
+
3
+ import { Button, Input, Switch, Tooltip } from 'antd'
4
+ import { useState } from 'react'
5
+
6
+ import type { TranslationFn } from '../configUtils'
7
+
8
+ export const BooleanRecordEditor = ({
9
+ value,
10
+ onChange,
11
+ t,
12
+ keyPlaceholder
13
+ }: {
14
+ value: Record<string, boolean>
15
+ onChange: (nextValue: Record<string, boolean>) => void
16
+ t: TranslationFn
17
+ keyPlaceholder: string
18
+ }) => {
19
+ const [newKey, setNewKey] = useState('')
20
+ const entries = Object.entries(value)
21
+
22
+ return (
23
+ <div className='config-view__record-list'>
24
+ {entries.map(([key, itemValue]) => (
25
+ <div key={key} className='config-view__record-row'>
26
+ <div className='config-view__record-key'>{key}</div>
27
+ <Switch
28
+ checked={Boolean(itemValue)}
29
+ onChange={(next) => {
30
+ onChange({ ...value, [key]: next })
31
+ }}
32
+ />
33
+ <Tooltip title={t('config.editor.remove')}>
34
+ <Button
35
+ size='small'
36
+ type='text'
37
+ danger
38
+ className='config-view__icon-button config-view__icon-button--compact'
39
+ aria-label={t('config.editor.remove')}
40
+ icon={<span className='material-symbols-rounded'>delete</span>}
41
+ onClick={() => {
42
+ const updated = { ...value }
43
+ delete updated[key]
44
+ onChange(updated)
45
+ }}
46
+ />
47
+ </Tooltip>
48
+ </div>
49
+ ))}
50
+ <div className='config-view__record-add'>
51
+ <div className='config-view__record-add-inputs'>
52
+ <Input
53
+ value={newKey}
54
+ placeholder={keyPlaceholder}
55
+ onChange={(event) => setNewKey(event.target.value)}
56
+ />
57
+ <Tooltip title={t('common.confirm')}>
58
+ <Button
59
+ size='small'
60
+ type='primary'
61
+ className='config-view__icon-button'
62
+ aria-label={t('common.confirm')}
63
+ icon={<span className='material-symbols-rounded'>check</span>}
64
+ disabled={newKey.trim() === '' || Object.hasOwn(value, newKey)}
65
+ onClick={() => {
66
+ onChange({ ...value, [newKey]: true })
67
+ setNewKey('')
68
+ }}
69
+ />
70
+ </Tooltip>
71
+ </div>
72
+ </div>
73
+ </div>
74
+ )
75
+ }
@@ -0,0 +1 @@
1
+ @use './RecordEditors.scss';
@@ -0,0 +1,97 @@
1
+ import './KeyValueEditor.scss'
2
+
3
+ import { Button, Input, Tooltip } from 'antd'
4
+ import { useState } from 'react'
5
+
6
+ import { isSensitiveKey } from '../configUtils'
7
+ import type { TranslationFn } from '../configUtils'
8
+
9
+ export const KeyValueEditor = ({
10
+ value,
11
+ onChange,
12
+ t,
13
+ keyPlaceholder
14
+ }: {
15
+ value: Record<string, string>
16
+ onChange: (nextValue: Record<string, string>) => void
17
+ t: TranslationFn
18
+ keyPlaceholder: string
19
+ }) => {
20
+ const [newKey, setNewKey] = useState('')
21
+ const [newValue, setNewValue] = useState('')
22
+ const entries = Object.entries(value)
23
+
24
+ return (
25
+ <div className='config-view__array-list'>
26
+ {entries.map(([key, val]) => (
27
+ <div key={key} className='config-view__array-item'>
28
+ <div className='config-view__record-key'>{key}</div>
29
+ {isSensitiveKey(key)
30
+ ? (
31
+ <Input.Password
32
+ value={val}
33
+ onChange={(event) => {
34
+ onChange({ ...value, [key]: event.target.value })
35
+ }}
36
+ placeholder={t('config.editor.fieldValue')}
37
+ />
38
+ )
39
+ : (
40
+ <Input
41
+ value={val}
42
+ onChange={(event) => {
43
+ onChange({ ...value, [key]: event.target.value })
44
+ }}
45
+ placeholder={t('config.editor.fieldValue')}
46
+ />
47
+ )}
48
+ <Tooltip title={t('config.editor.remove')}>
49
+ <Button
50
+ size='small'
51
+ type='text'
52
+ danger
53
+ className='config-view__icon-button config-view__icon-button--compact'
54
+ aria-label={t('config.editor.remove')}
55
+ icon={<span className='material-symbols-rounded'>delete</span>}
56
+ onClick={() => {
57
+ const updated = { ...value }
58
+ delete updated[key]
59
+ onChange(updated)
60
+ }}
61
+ />
62
+ </Tooltip>
63
+ </div>
64
+ ))}
65
+ <div className='config-view__array-add'>
66
+ <div className='config-view__array-add-inputs'>
67
+ <Input
68
+ value={newKey}
69
+ placeholder={keyPlaceholder}
70
+ onChange={(event) => setNewKey(event.target.value)}
71
+ />
72
+ <Input
73
+ value={newValue}
74
+ placeholder={t('config.editor.fieldValue')}
75
+ onChange={(event) => setNewValue(event.target.value)}
76
+ />
77
+ <Tooltip title={t('common.confirm')}>
78
+ <Button
79
+ size='small'
80
+ type='primary'
81
+ className='config-view__icon-button'
82
+ aria-label={t('common.confirm')}
83
+ icon={<span className='material-symbols-rounded'>check</span>}
84
+ disabled={newKey.trim() === '' || Object.hasOwn(value, newKey)}
85
+ onClick={() => {
86
+ const nextValue = { ...value, [newKey]: newValue }
87
+ onChange(nextValue)
88
+ setNewKey('')
89
+ setNewValue('')
90
+ }}
91
+ />
92
+ </Tooltip>
93
+ </div>
94
+ </div>
95
+ </div>
96
+ )
97
+ }
@@ -0,0 +1 @@
1
+ @use './RecordEditors.scss';