@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
@@ -2,9 +2,10 @@ import React from 'react'
2
2
 
3
3
  import type { ChatMessageContent } from '@vibe-forge/core'
4
4
 
5
- import { DefaultTool } from './tools/DefaultTool'
6
- import { BashTool, adapterClaudeToolRenders } from './tools/adapter-claude'
7
- import { taskToolRenders } from './tools/task'
5
+ import { DefaultTool } from '../DefaultTool'
6
+ import { BashTool, adapterClaudeToolRenders } from '../adapter-claude'
7
+ import { chromeDevtoolsToolRenders } from '../plugin-chrome-devtools'
8
+ import { taskToolRenders } from '../task'
8
9
 
9
10
  const TOOL_RENDERERS: Record<
10
11
  string,
@@ -14,7 +15,8 @@ const TOOL_RENDERERS: Record<
14
15
  }>
15
16
  > = {
16
17
  ...taskToolRenders,
17
- ...adapterClaudeToolRenders
18
+ ...adapterClaudeToolRenders,
19
+ ...chromeDevtoolsToolRenders
18
20
  }
19
21
 
20
22
  export function ToolRenderer({
@@ -0,0 +1,11 @@
1
+ .chrome-devtools-tool {
2
+ &__icon {
3
+ color: unset;
4
+ }
5
+
6
+ .tool-content {
7
+ display: flex;
8
+ flex-direction: column;
9
+ gap: 12px;
10
+ }
11
+ }
@@ -0,0 +1,75 @@
1
+ import './ChromeDevtoolsTool.scss'
2
+ import React from 'react'
3
+ import { useTranslation } from 'react-i18next'
4
+
5
+ import { CodeBlock } from '#~/components/CodeBlock'
6
+ import { ToolCallBox } from '../core/ToolCallBox'
7
+ import { safeJsonStringify } from '#~/utils/safe-serialize'
8
+ import { defineToolRender } from '../defineToolRender'
9
+
10
+ const formatToolName = (name: string) => {
11
+ if (name.startsWith('mcp__ChromeDevtools__')) {
12
+ return name.replace('mcp__ChromeDevtools__', '')
13
+ }
14
+ return name
15
+ }
16
+
17
+ export const ChromeDevtoolsTool = defineToolRender(({ item, resultItem }) => {
18
+ const { t } = useTranslation()
19
+ const displayName = formatToolName(item.name)
20
+ const input = item.input != null ? item.input : {}
21
+
22
+ return (
23
+ <div className='tool-group chrome-devtools-tool'>
24
+ <ToolCallBox
25
+ defaultExpanded={true}
26
+ header={
27
+ <div className='tool-header-content'>
28
+ <i className='tool-header-icon chrome-devtools-tool__icon devicon-chrome-plain colored' />
29
+ <span className='tool-header-title'>{displayName}</span>
30
+ <span className='tool-header-hint'>{t('chat.tools.call')}</span>
31
+ </div>
32
+ }
33
+ content={
34
+ <div className='tool-content'>
35
+ <CodeBlock
36
+ code={safeJsonStringify(input, 2)}
37
+ lang='json'
38
+ />
39
+ </div>
40
+ }
41
+ />
42
+ {resultItem != null && (
43
+ <ToolCallBox
44
+ type='result'
45
+ isError={resultItem.is_error}
46
+ header={
47
+ <div className='tool-header-content'>
48
+ <span className='material-symbols-rounded tool-header-icon'>
49
+ {resultItem.is_error === true ? 'error' : 'check_circle'}
50
+ </span>
51
+ <span className='tool-header-title'>{t('chat.result')}</span>
52
+ </div>
53
+ }
54
+ content={
55
+ <div className='tool-content'>
56
+ {typeof resultItem.content === 'string'
57
+ ? (
58
+ <CodeBlock
59
+ code={resultItem.content}
60
+ lang='text'
61
+ />
62
+ )
63
+ : (
64
+ <CodeBlock
65
+ code={safeJsonStringify(resultItem.content, 2)}
66
+ lang='json'
67
+ />
68
+ )}
69
+ </div>
70
+ }
71
+ />
72
+ )}
73
+ </div>
74
+ )
75
+ })
@@ -0,0 +1,45 @@
1
+ import type { ChromeDevtoolsToolName } from '@vibe-forge/plugin-chrome-devtools/schema'
2
+
3
+ import type { ToolRenderComponent } from '../defineToolRender'
4
+ import { defineToolRenders } from '../defineToolRender'
5
+ import { ChromeDevtoolsTool } from './ChromeDevtoolsTool'
6
+
7
+ const chromeDevtoolsToolNames: ChromeDevtoolsToolName[] = [
8
+ 'mcp__ChromeDevtools__click',
9
+ 'mcp__ChromeDevtools__close_page',
10
+ 'mcp__ChromeDevtools__drag',
11
+ 'mcp__ChromeDevtools__emulate',
12
+ 'mcp__ChromeDevtools__evaluate_script',
13
+ 'mcp__ChromeDevtools__fill',
14
+ 'mcp__ChromeDevtools__fill_form',
15
+ 'mcp__ChromeDevtools__get_console_message',
16
+ 'mcp__ChromeDevtools__get_network_request',
17
+ 'mcp__ChromeDevtools__handle_dialog',
18
+ 'mcp__ChromeDevtools__hover',
19
+ 'mcp__ChromeDevtools__list_console_messages',
20
+ 'mcp__ChromeDevtools__list_network_requests',
21
+ 'mcp__ChromeDevtools__list_pages',
22
+ 'mcp__ChromeDevtools__navigate_page',
23
+ 'mcp__ChromeDevtools__new_page',
24
+ 'mcp__ChromeDevtools__performance_analyze_insight',
25
+ 'mcp__ChromeDevtools__performance_start_trace',
26
+ 'mcp__ChromeDevtools__performance_stop_trace',
27
+ 'mcp__ChromeDevtools__press_key',
28
+ 'mcp__ChromeDevtools__resize_page',
29
+ 'mcp__ChromeDevtools__select_page',
30
+ 'mcp__ChromeDevtools__take_memory_snapshot',
31
+ 'mcp__ChromeDevtools__take_screenshot',
32
+ 'mcp__ChromeDevtools__take_snapshot',
33
+ 'mcp__ChromeDevtools__type_text',
34
+ 'mcp__ChromeDevtools__upload_file',
35
+ 'mcp__ChromeDevtools__wait_for'
36
+ ]
37
+
38
+ const chromeDevtoolsToolEntries = chromeDevtoolsToolNames.reduce<Record<string, ToolRenderComponent>>((acc, name) => {
39
+ acc[name] = ChromeDevtoolsTool
40
+ return acc
41
+ }, {})
42
+
43
+ export const chromeDevtoolsToolRenders = defineToolRenders(chromeDevtoolsToolEntries)
44
+
45
+ export { ChromeDevtoolsTool }
@@ -13,34 +13,9 @@
13
13
  );
14
14
  }
15
15
 
16
- &__header {
17
- display: flex;
18
- align-items: center;
19
- gap: 8px;
20
- }
21
-
22
- &__icon {
23
- font-size: 16px;
24
- }
25
-
26
- &__title {
27
- font-weight: 600;
28
- }
29
-
30
- &__count {
31
- margin-left: 4px;
32
- padding: 1px 6px;
33
- border: 1px solid var(--border-color);
34
- border-radius: 999px;
35
- font-size: 11px;
36
- font-weight: 600;
37
- color: var(--sub-text-color);
38
- background: color-mix(in srgb, var(--bg-color) 70%, transparent 30%);
39
- }
40
-
41
16
  &__empty {
42
- margin: 10px 12px;
43
- padding: 10px 12px;
17
+ margin: 0;
18
+ padding: 8px 10px;
44
19
  border: 1px dashed var(--border-color);
45
20
  border-radius: 8px;
46
21
  font-size: 12px;
@@ -2,10 +2,11 @@ import './GetTaskInfoTool.scss'
2
2
 
3
3
  import React, { useMemo } from 'react'
4
4
  import { useTranslation } from 'react-i18next'
5
+ import type { ToolInputs } from '@vibe-forge/core'
5
6
 
7
+ import { ToolCallBox } from '../core/ToolCallBox'
6
8
  import { defineToolRender } from '../defineToolRender'
7
- import { ToolCallBox } from '../../ToolCallBox'
8
- import { TaskToolCard } from './components/TaskToolCard'
9
+ import { TaskRow } from './components/TaskRow'
9
10
 
10
11
  interface TaskResult {
11
12
  taskId: string
@@ -22,7 +23,7 @@ interface TaskResult {
22
23
  export const GetTaskInfoTool = defineToolRender(({ item, resultItem }) => {
23
24
  const { t } = useTranslation()
24
25
 
25
- const input = (item.input != null ? item.input : {}) as { taskId?: string }
26
+ const input = (item.input != null ? item.input : {}) as Partial<ToolInputs['GetTaskInfo']>
26
27
  const inputTaskId = input.taskId
27
28
 
28
29
  const taskResult = useMemo(() => {
@@ -34,18 +35,23 @@ export const GetTaskInfoTool = defineToolRender(({ item, resultItem }) => {
34
35
  return parsed[0] ?? null
35
36
  }, [resultItem?.content])
36
37
 
37
- const logs = taskResult?.logs ?? []
38
- const metaChips = taskResult ? (() => {
39
- const { exitCode, ...cardMeta } = taskResult
40
- return [
41
- cardMeta.adapter,
42
- cardMeta.type === 'default' ? undefined : cardMeta.type,
43
- cardMeta.name,
44
- cardMeta.status,
45
- exitCode != null ? t('chat.tools.taskExitCode', { code: exitCode }) : undefined,
46
- cardMeta.background === false ? t('chat.tools.startTasksForeground') : cardMeta.background === true ? t('chat.tools.startTasksBackground') : undefined
47
- ]
48
- })() : []
38
+ const metaChips = taskResult
39
+ ? (() => {
40
+ const { exitCode, ...cardMeta } = taskResult
41
+ return [
42
+ cardMeta.adapter,
43
+ cardMeta.type === 'default' ? undefined : cardMeta.type,
44
+ cardMeta.name,
45
+ cardMeta.status,
46
+ exitCode != null ? t('chat.tools.taskExitCode', { code: exitCode }) : undefined,
47
+ cardMeta.background === false
48
+ ? t('chat.tools.startTasksForeground')
49
+ : cardMeta.background === true
50
+ ? t('chat.tools.startTasksBackground')
51
+ : undefined
52
+ ]
53
+ })()
54
+ : []
49
55
  const titleFallback = t('chat.tools.task')
50
56
 
51
57
  return (
@@ -53,33 +59,37 @@ export const GetTaskInfoTool = defineToolRender(({ item, resultItem }) => {
53
59
  <ToolCallBox
54
60
  defaultExpanded={true}
55
61
  header={
56
- <div className='get-task-info-tool__header'>
57
- <span className='material-symbols-rounded get-task-info-tool__icon'>info</span>
58
- <span className='get-task-info-tool__title'>{t('chat.tools.getTaskInfo')}</span>
59
- <span className='get-task-info-tool__count'>{taskResult ? 1 : 0}</span>
62
+ <div className='tool-header-content'>
63
+ <span className='material-symbols-rounded tool-header-icon'>info</span>
64
+ <span className='tool-header-title'>{t('chat.tools.getTaskInfo')}</span>
65
+ <span className='tool-header-chip'>{taskResult ? 1 : 0}</span>
60
66
  </div>
61
67
  }
62
68
  content={
63
69
  <div className='tool-content'>
64
- {taskResult ? (
65
- (() => {
66
- const { taskId, exitCode, ...cardProps } = taskResult
67
- return (
68
- <TaskToolCard
69
- {...cardProps}
70
- logs={logs}
71
- sessionId={taskId || inputTaskId}
72
- titleFallback={titleFallback}
73
- metaChips={metaChips}
74
- showExecutionIcon={false}
75
- />
76
- )
77
- })()
78
- ) : (
79
- <div className='get-task-info-tool__empty'>
80
- {t('chat.tools.startTasksEmpty')}
81
- </div>
82
- )}
70
+ {taskResult
71
+ ? (
72
+ (() => {
73
+ const { taskId, exitCode, ...cardProps } = taskResult
74
+ return (
75
+ <TaskRow
76
+ description={cardProps.description}
77
+ status={cardProps.status}
78
+ background={cardProps.background}
79
+ sessionId={taskId || inputTaskId}
80
+ logs={cardProps.logs}
81
+ titleFallback={titleFallback}
82
+ metaChips={metaChips}
83
+ showExecutionIcon={false}
84
+ />
85
+ )
86
+ })()
87
+ )
88
+ : (
89
+ <div className='get-task-info-tool__empty'>
90
+ {t('chat.tools.startTasksEmpty')}
91
+ </div>
92
+ )}
83
93
  </div>
84
94
  }
85
95
  />
@@ -13,40 +13,15 @@
13
13
  );
14
14
  }
15
15
 
16
- &__header {
17
- display: flex;
18
- align-items: center;
19
- gap: 8px;
20
- }
21
-
22
- &__icon {
23
- font-size: 16px;
24
- }
25
-
26
- &__title {
27
- font-weight: 600;
28
- }
29
-
30
- &__count {
31
- margin-left: 4px;
32
- padding: 1px 6px;
33
- border: 1px solid var(--border-color);
34
- border-radius: 999px;
35
- font-size: 11px;
36
- font-weight: 600;
37
- color: var(--sub-text-color);
38
- background: color-mix(in srgb, var(--bg-color) 70%, transparent 30%);
39
- }
40
-
41
16
  &__list {
42
- padding: 10px 12px;
17
+ padding: 0;
43
18
  display: flex;
44
19
  flex-direction: column;
45
- gap: 8px;
20
+ gap: 0;
46
21
  }
47
22
 
48
23
  &__empty {
49
- padding: 10px 12px;
24
+ padding: 8px 10px;
50
25
  border: 1px dashed var(--border-color);
51
26
  border-radius: 8px;
52
27
  font-size: 12px;
@@ -3,9 +3,9 @@ import './ListTasksTool.scss'
3
3
  import React, { useMemo } from 'react'
4
4
  import { useTranslation } from 'react-i18next'
5
5
 
6
- import { ToolCallBox } from '../../ToolCallBox'
6
+ import { ToolCallBox } from '../core/ToolCallBox'
7
7
  import { defineToolRender } from '../defineToolRender'
8
- import { TaskToolCard } from './components/TaskToolCard'
8
+ import { TaskRow } from './components/TaskRow'
9
9
 
10
10
  interface TaskResult {
11
11
  taskId: string
@@ -35,10 +35,10 @@ export const ListTasksTool = defineToolRender(({ resultItem }) => {
35
35
  <ToolCallBox
36
36
  defaultExpanded={true}
37
37
  header={
38
- <div className='list-tasks-tool__header'>
39
- <span className='material-symbols-rounded list-tasks-tool__icon'>list_alt</span>
40
- <span className='list-tasks-tool__title'>{t('chat.tools.listTasks')}</span>
41
- <span className='list-tasks-tool__count'>{taskResults.length}</span>
38
+ <div className='tool-header-content'>
39
+ <span className='material-symbols-rounded tool-header-icon'>list_alt</span>
40
+ <span className='tool-header-title'>{t('chat.tools.listTasks')}</span>
41
+ <span className='tool-header-chip'>{taskResults.length}</span>
42
42
  </div>
43
43
  }
44
44
  content={
@@ -59,10 +59,13 @@ export const ListTasksTool = defineToolRender(({ resultItem }) => {
59
59
  : undefined
60
60
  ]
61
61
  return (
62
- <TaskToolCard
62
+ <TaskRow
63
63
  key={taskId}
64
- {...cardProps}
64
+ description={cardProps.description}
65
+ status={cardProps.status}
66
+ background={cardProps.background}
65
67
  sessionId={taskId}
68
+ logs={cardProps.logs}
66
69
  titleFallback={t('chat.tools.task')}
67
70
  metaChips={metaChips}
68
71
  showExecutionIcon={false}
@@ -13,40 +13,15 @@
13
13
  );
14
14
  }
15
15
 
16
- &__header {
17
- display: flex;
18
- align-items: center;
19
- gap: 8px;
20
- }
21
-
22
- &__icon {
23
- font-size: 16px;
24
- }
25
-
26
- &__title {
27
- font-weight: 600;
28
- }
29
-
30
- &__count {
31
- margin-left: 4px;
32
- padding: 1px 6px;
33
- border: 1px solid var(--border-color);
34
- border-radius: 999px;
35
- font-size: 11px;
36
- font-weight: 600;
37
- color: var(--sub-text-color);
38
- background: color-mix(in srgb, var(--bg-color) 70%, transparent 30%);
39
- }
40
-
41
16
  &__list {
42
- padding: 10px 12px;
17
+ padding: 0;
43
18
  display: flex;
44
19
  flex-direction: column;
45
- gap: 8px;
20
+ gap: 0;
46
21
  }
47
22
 
48
23
  &__empty {
49
- padding: 10px 12px;
24
+ padding: 8px 10px;
50
25
  border: 1px dashed var(--border-color);
51
26
  border-radius: 8px;
52
27
  font-size: 12px;
@@ -2,18 +2,13 @@ import './StartTasksTool.scss'
2
2
 
3
3
  import React, { useMemo } from 'react'
4
4
  import { useTranslation } from 'react-i18next'
5
+ import type { ToolInputs } from '@vibe-forge/core'
5
6
 
6
- import { ToolCallBox } from '../../ToolCallBox'
7
+ import { ToolCallBox } from '../core/ToolCallBox'
7
8
  import { defineToolRender } from '../defineToolRender'
8
- import { TaskToolCard } from './components/TaskToolCard'
9
+ import { TaskRow } from './components/TaskRow'
9
10
 
10
- interface StartTask {
11
- description?: string
12
- type?: 'default' | 'spec' | 'entity'
13
- name?: string
14
- adapter?: string
15
- background?: boolean
16
- }
11
+ type StartTask = ToolInputs['StartTasks']['tasks'][number]
17
12
 
18
13
  interface TaskResult {
19
14
  taskId: string
@@ -30,7 +25,7 @@ interface TaskResult {
30
25
  export const StartTasksTool = defineToolRender(({ item, resultItem }) => {
31
26
  const { t } = useTranslation()
32
27
 
33
- const input = (item.input != null ? item.input : {}) as { tasks?: StartTask[] }
28
+ const input = (item.input != null ? item.input : {}) as Partial<ToolInputs['StartTasks']>
34
29
  const tasks = Array.isArray(input.tasks) ? input.tasks : []
35
30
 
36
31
  const parsedResult = useMemo(() => {
@@ -50,10 +45,10 @@ export const StartTasksTool = defineToolRender(({ item, resultItem }) => {
50
45
  <ToolCallBox
51
46
  defaultExpanded={true}
52
47
  header={
53
- <div className='start-tasks-tool__header'>
54
- <span className='material-symbols-rounded start-tasks-tool__icon'>playlist_add</span>
55
- <span className='start-tasks-tool__title'>{t('chat.tools.startTasks')}</span>
56
- <span className='start-tasks-tool__count'>{tasks.length}</span>
48
+ <div className='tool-header-content'>
49
+ <span className='material-symbols-rounded tool-header-icon'>playlist_add</span>
50
+ <span className='tool-header-title'>{t('chat.tools.startTasks')}</span>
51
+ <span className='tool-header-chip'>{tasks.length}</span>
57
52
  </div>
58
53
  }
59
54
  content={
@@ -62,7 +57,6 @@ export const StartTasksTool = defineToolRender(({ item, resultItem }) => {
62
57
  {tasks.map((task, idx) => {
63
58
  const { description, type, name, adapter, background } = task
64
59
  const { status, taskId, logs = [] } = taskResults?.[idx] ?? {}
65
- const cardProps = { description, status, logs, adapter, type, name, background }
66
60
  const metaChips = [
67
61
  adapter,
68
62
  type === 'default' ? undefined : type,
@@ -70,10 +64,13 @@ export const StartTasksTool = defineToolRender(({ item, resultItem }) => {
70
64
  ]
71
65
 
72
66
  return (
73
- <TaskToolCard
67
+ <TaskRow
74
68
  key={idx}
75
- {...cardProps}
69
+ description={description}
70
+ status={status}
71
+ background={background}
76
72
  sessionId={taskId}
73
+ logs={logs}
77
74
  titleFallback={t('chat.tools.startTasks')}
78
75
  metaChips={metaChips}
79
76
  showExecutionIcon={true}
@@ -0,0 +1,105 @@
1
+ .task-row {
2
+ display: flex;
3
+ flex-direction: column;
4
+ align-items: stretch;
5
+ gap: 6px;
6
+ min-width: 0;
7
+ padding: 6px 8px;
8
+ border-bottom: 1px solid var(--border-color);
9
+ }
10
+
11
+ .task-row:last-child {
12
+ border-bottom: none;
13
+ }
14
+
15
+ .task-row__header {
16
+ display: flex;
17
+ align-items: center;
18
+ gap: 8px;
19
+ min-width: 0;
20
+ }
21
+
22
+ .task-row__left {
23
+ display: flex;
24
+ align-items: center;
25
+ gap: 6px;
26
+ flex-shrink: 0;
27
+ }
28
+
29
+ .task-row__status-icon {
30
+ font-size: 16px;
31
+ color: var(--sub-text-color);
32
+ }
33
+
34
+ .task-row__status-icon.running {
35
+ color: var(--primary-color);
36
+ }
37
+
38
+ .task-row__status-icon.completed {
39
+ color: var(--success-color);
40
+ }
41
+
42
+ .task-row__status-icon.failed {
43
+ color: var(--danger-color);
44
+ }
45
+
46
+ .task-row__execution-icon {
47
+ font-size: 16px;
48
+ color: var(--sub-text-color);
49
+ }
50
+
51
+ .task-row__execution-icon--foreground {
52
+ color: var(--primary-color);
53
+ }
54
+
55
+ .task-row__execution-icon--background {
56
+ color: var(--sub-text-color);
57
+ }
58
+
59
+ .task-row__title {
60
+ min-width: 0;
61
+ flex: 1;
62
+ overflow: hidden;
63
+ text-overflow: ellipsis;
64
+ white-space: nowrap;
65
+ font-size: 12px;
66
+ color: var(--text-color);
67
+ }
68
+
69
+ .task-row__session-link {
70
+ border: none;
71
+ background: transparent;
72
+ padding: 0;
73
+ margin: 0;
74
+ cursor: pointer;
75
+ font-size: 11px;
76
+ color: var(--primary-color);
77
+ font-family: var(--font-mono);
78
+ flex-shrink: 0;
79
+ }
80
+
81
+ .task-row__session-link:hover {
82
+ text-shadow: 0 0 .5px currentColor;
83
+ }
84
+
85
+ .task-row__meta {
86
+ display: flex;
87
+ align-items: center;
88
+ gap: 6px;
89
+ flex-shrink: 0;
90
+ }
91
+
92
+ .task-row__meta-chip {
93
+ padding: 1px 6px;
94
+ border: 1px solid var(--border-color);
95
+ border-radius: 999px;
96
+ font-size: 10px;
97
+ font-weight: 600;
98
+ color: var(--sub-text-color);
99
+ background: var(--bg-color);
100
+ white-space: nowrap;
101
+ }
102
+
103
+ .task-row__logs {
104
+ width: 100%;
105
+ }