@vibe-forge/client 0.2.0-alpha.9 → 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 (166) hide show
  1. package/cli.cjs +1 -1
  2. package/dist/assets/{arc-CybT1Fs2.js → arc-DgIxeTMg.js} +1 -1
  3. package/dist/assets/{blockDiagram-c4efeb88-BY5Aoa-D.js → blockDiagram-c4efeb88-CEAob3X9.js} +1 -1
  4. package/dist/assets/{c4Diagram-c83219d4-F42hTbzS.js → c4Diagram-c83219d4-DwIxpDKd.js} +1 -1
  5. package/dist/assets/channel-DhtnrNJ6.js +1 -0
  6. package/dist/assets/{classDiagram-beda092f-D-tIPp-3.js → classDiagram-beda092f-Cz1q8u_0.js} +1 -1
  7. package/dist/assets/{classDiagram-v2-2358418a-J57aCe6u.js → classDiagram-v2-2358418a-CImgTuwd.js} +1 -1
  8. package/dist/assets/clone-7bHB6YkC.js +1 -0
  9. package/dist/assets/{createText-1719965b-ByfEqOF-.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-CMEArkOa.js → edges-96097737-BU8qStzd.js} +1 -1
  15. package/dist/assets/{erDiagram-0228fc6a-Cf8mX2aj.js → erDiagram-0228fc6a-DNA1Fz2L.js} +1 -1
  16. package/dist/assets/{flowDb-c6c81e3f-DG6WKyo7.js → flowDb-c6c81e3f-DjiCStMN.js} +1 -1
  17. package/dist/assets/{flowDiagram-50d868cf-CstUxz-w.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--4CRoQ-H.js → flowchart-elk-definition-6af322e1-DrhIMas7.js} +1 -1
  20. package/dist/assets/{ganttDiagram-a2739b55-DYgHcKd-.js → ganttDiagram-a2739b55-CTZnUP5z.js} +1 -1
  21. package/dist/assets/{gitGraphDiagram-82fe8481-DDSVpfsd.js → gitGraphDiagram-82fe8481-COOW7jTi.js} +1 -1
  22. package/dist/assets/{graph-CRWF39gX.js → graph-CIkpD4Kx.js} +1 -1
  23. package/dist/assets/{index-5325376f-W1hft795.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-D4SHcix6.js → infoDiagram-8eee0895-DQpZ1LVD.js} +1 -1
  27. package/dist/assets/{journeyDiagram-c64418c1-MWgCkVoE.js → journeyDiagram-c64418c1-DoKguIuk.js} +1 -1
  28. package/dist/assets/{layout-C88ObkCf.js → layout-Tnmha8Nh.js} +1 -1
  29. package/dist/assets/{line-C7WAYMt5.js → line-BQR2SOyl.js} +1 -1
  30. package/dist/assets/{linear-C4msxfcU.js → linear-DlG0eemV.js} +1 -1
  31. package/dist/assets/{mermaid.core-Cabag9SZ.js → mermaid.core-BnwYO0He.js} +6 -6
  32. package/dist/assets/{mindmap-definition-8da855dc-CeS8ETXx.js → mindmap-definition-8da855dc-BllYwDID.js} +1 -1
  33. package/dist/assets/{pieDiagram-a8764435-BvjyKnq5.js → pieDiagram-a8764435-DwCkhPVc.js} +1 -1
  34. package/dist/assets/{quadrantDiagram-1e28029f-DzYvpbNM.js → quadrantDiagram-1e28029f-c40GKTU0.js} +1 -1
  35. package/dist/assets/{requirementDiagram-08caed73-DHIoDbyo.js → requirementDiagram-08caed73-DnQp2Tk6.js} +1 -1
  36. package/dist/assets/{sankeyDiagram-a04cb91d-BFSGnQGs.js → sankeyDiagram-a04cb91d-CnJrs13b.js} +1 -1
  37. package/dist/assets/{sequenceDiagram-c5b8d532-_LM3BJ5-.js → sequenceDiagram-c5b8d532-1YBwnpKu.js} +1 -1
  38. package/dist/assets/{stateDiagram-1ecb1508-DwORjOzl.js → stateDiagram-1ecb1508-BFBxQ6Fh.js} +1 -1
  39. package/dist/assets/{stateDiagram-v2-c2b004d7-B4cAWWz1.js → stateDiagram-v2-c2b004d7-Dmechvv2.js} +1 -1
  40. package/dist/assets/{styles-b4e223ce-D_rmV3B_.js → styles-b4e223ce-DWWfWX8O.js} +1 -1
  41. package/dist/assets/{styles-ca3715f6-BFx4VuFc.js → styles-ca3715f6-CKKvZxaU.js} +1 -1
  42. package/dist/assets/{styles-d45a18b0-BE3106vL.js → styles-d45a18b0-dKMOUh9p.js} +1 -1
  43. package/dist/assets/{svgDrawCommon-b86b1483-DwDTO1op.js → svgDrawCommon-b86b1483-CBgjChPM.js} +1 -1
  44. package/dist/assets/{timeline-definition-faaaa080-C4b8qUQZ.js → timeline-definition-faaaa080-NCt-HHmb.js} +1 -1
  45. package/dist/assets/{xychartDiagram-f5964ef8-BRJ9Z4u-.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 -241
  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 +13 -1
  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/NewSessionGuide.scss +35 -13
  86. package/src/components/chat/NewSessionGuide.tsx +20 -10
  87. package/src/components/chat/{Sender.scss → Sender/Sender.scss} +80 -0
  88. package/src/components/chat/{Sender.tsx → Sender/Sender.tsx} +161 -5
  89. package/src/components/chat/tools/DefaultTool.tsx +184 -21
  90. package/src/components/chat/tools/adapter-claude/BashTool.scss +67 -51
  91. package/src/components/chat/tools/adapter-claude/BashTool.tsx +83 -49
  92. package/src/components/chat/tools/adapter-claude/GlobTool.scss +0 -79
  93. package/src/components/chat/tools/adapter-claude/GlobTool.tsx +16 -36
  94. package/src/components/chat/tools/adapter-claude/GrepTool.scss +0 -87
  95. package/src/components/chat/tools/adapter-claude/GrepTool.tsx +22 -41
  96. package/src/components/chat/tools/adapter-claude/LSTool.scss +0 -79
  97. package/src/components/chat/tools/adapter-claude/LSTool.tsx +15 -15
  98. package/src/components/chat/tools/adapter-claude/ReadTool.scss +0 -55
  99. package/src/components/chat/tools/adapter-claude/ReadTool.tsx +20 -42
  100. package/src/components/chat/tools/adapter-claude/TodoTool.scss +8 -23
  101. package/src/components/chat/tools/adapter-claude/TodoTool.tsx +24 -11
  102. package/src/components/chat/tools/adapter-claude/WriteTool.scss +21 -69
  103. package/src/components/chat/tools/adapter-claude/WriteTool.tsx +22 -58
  104. package/src/components/chat/tools/adapter-claude/index.ts +4 -10
  105. package/src/components/chat/tools/adapter-claude/utils.ts +54 -0
  106. package/src/components/chat/tools/core/ToolCallBox.scss +356 -0
  107. package/src/components/chat/{ToolGroup.tsx → tools/core/ToolGroup.tsx} +26 -7
  108. package/src/components/chat/{ToolRenderer.tsx → tools/core/ToolRenderer.tsx} +6 -4
  109. package/src/components/chat/tools/plugin-chrome-devtools/ChromeDevtoolsTool.scss +11 -0
  110. package/src/components/chat/tools/plugin-chrome-devtools/ChromeDevtoolsTool.tsx +75 -0
  111. package/src/components/chat/tools/plugin-chrome-devtools/index.ts +45 -0
  112. package/src/components/chat/tools/task/GetTaskInfoTool.scss +2 -27
  113. package/src/components/chat/tools/task/GetTaskInfoTool.tsx +48 -38
  114. package/src/components/chat/tools/task/ListTasksTool.scss +3 -28
  115. package/src/components/chat/tools/task/ListTasksTool.tsx +11 -8
  116. package/src/components/chat/tools/task/StartTasksTool.scss +3 -28
  117. package/src/components/chat/tools/task/StartTasksTool.tsx +14 -17
  118. package/src/components/chat/tools/task/components/TaskRow.scss +105 -0
  119. package/src/components/chat/tools/task/components/TaskRow.tsx +163 -0
  120. package/src/components/chat/tools/task/components/TaskToolCard.scss +15 -15
  121. package/src/components/chat/tools/task/components/TaskToolCard.tsx +8 -6
  122. package/src/components/config/AppSettingsPanel.tsx +33 -0
  123. package/src/components/config/ConfigSectionForm.tsx +12 -1
  124. package/src/components/config/channelDefinitions.ts +6 -0
  125. package/src/components/config/configSchema.ts +10 -1
  126. package/src/components/config/recordEditors/ChannelRecordEditor.scss +1 -0
  127. package/src/components/config/recordEditors/ChannelRecordEditor.tsx +397 -0
  128. package/src/components/config/recordEditors/index.tsx +1 -0
  129. package/src/components/knowledge-base/KnowledgeBaseView.tsx +51 -3
  130. package/src/components/knowledge-base/components/RuleItem.tsx +79 -0
  131. package/src/components/knowledge-base/components/RuleList.scss +5 -0
  132. package/src/components/knowledge-base/components/RuleList.tsx +70 -0
  133. package/src/components/knowledge-base/components/RulesTab.tsx +32 -7
  134. package/src/components/knowledge-base/components/SpecItem.tsx +1 -1
  135. package/src/hooks/chat/use-chat-interaction.ts +26 -0
  136. package/src/{components/chat/useChatModels.tsx → hooks/chat/use-chat-models.tsx} +65 -16
  137. package/src/hooks/chat/use-chat-permission-mode.ts +47 -0
  138. package/src/hooks/chat/use-chat-scroll.ts +51 -0
  139. package/src/hooks/chat/use-chat-session-actions.ts +147 -0
  140. package/src/hooks/chat/use-chat-session-messages.ts +250 -0
  141. package/src/hooks/chat/use-chat-session.ts +57 -0
  142. package/src/hooks/chat/use-chat-view.ts +39 -0
  143. package/src/main.tsx +10 -13
  144. package/src/resources/locales/en.json +73 -0
  145. package/src/resources/locales/zh.json +73 -0
  146. package/src/runtime-config.ts +52 -0
  147. package/src/store/index.ts +2 -0
  148. package/src/vite-env.d.ts +11 -0
  149. package/src/ws.ts +5 -3
  150. package/vite.config.ts +12 -4
  151. package/dist/assets/channel-DrWdSpqV.js +0 -1
  152. package/dist/assets/clone-D0cC8LLB.js +0 -1
  153. package/dist/assets/flowDiagram-v2-4f6560a1-Bf_DH7dp.js +0 -1
  154. package/dist/assets/index-CNMzWvKV.js +0 -497
  155. package/dist/assets/index-PEmISxiy.css +0 -1
  156. package/src/components/chat/ToolCallBox.scss +0 -137
  157. package/src/components/chat/useChatSession.ts +0 -370
  158. /package/src/components/{chat/CodeBlock.scss → CodeBlock.scss} +0 -0
  159. /package/src/components/chat/{MessageFooter.tsx → Messages/MessageFooter.tsx} +0 -0
  160. /package/src/components/chat/{CompletionMenu.scss → Sender/CompletionMenu.scss} +0 -0
  161. /package/src/components/chat/{CompletionMenu.tsx → Sender/CompletionMenu.tsx} +0 -0
  162. /package/src/components/chat/{ThinkingStatus.scss → Sender/ThinkingStatus.scss} +0 -0
  163. /package/src/components/chat/{ThinkingStatus.tsx → Sender/ThinkingStatus.tsx} +0 -0
  164. /package/src/components/chat/{ToolCallBox.tsx → tools/core/ToolCallBox.tsx} +0 -0
  165. /package/src/components/chat/{ToolGroup.scss → tools/core/ToolGroup.scss} +0 -0
  166. /package/src/{components/chat/safeSerialize.ts → utils/safe-serialize.ts} +0 -0
@@ -1,22 +1,15 @@
1
1
  import './BashTool.scss'
2
- import React from 'react'
2
+ import type { ToolInputs } from '@vibe-forge/core'
3
+ import React, { useState } from 'react'
3
4
  import { useTranslation } from 'react-i18next'
4
- import ReactMarkdown from 'react-markdown'
5
- import remarkGfm from 'remark-gfm'
6
-
5
+ import { CodeBlock } from '#~/components/CodeBlock'
6
+ import { ToolCallBox } from '../core/ToolCallBox'
7
+ import { safeJsonStringify } from '#~/utils/safe-serialize'
7
8
  import { defineToolRender } from '../defineToolRender'
8
- import { CodeBlock } from '../../CodeBlock'
9
- import { ToolCallBox } from '../../ToolCallBox'
10
- import { safeJsonStringify } from '../../safeSerialize'
11
9
 
12
10
  export const BashTool = defineToolRender(({ item, resultItem }) => {
13
11
  const { t } = useTranslation()
14
- const input = (item.input != null ? item.input : {}) as {
15
- command?: string
16
- reason?: string
17
- thought?: string
18
- description?: string
19
- }
12
+ const input = (item.input != null ? item.input : {}) as Partial<ToolInputs['adapter:claude-code:Bash']>
20
13
  const command = input.command ?? ''
21
14
  const reason = (input.description != null && input.description !== '')
22
15
  ? input.description
@@ -25,58 +18,99 @@ export const BashTool = defineToolRender(({ item, resultItem }) => {
25
18
  : (input.thought != null && input.thought !== '')
26
19
  ? input.thought
27
20
  : ''
21
+ const timeout = input.timeout
22
+ const runInBackground = input.run_in_background
23
+ const dangerouslyDisableSandbox = input.dangerouslyDisableSandbox
24
+ const reasonLine = reason.replaceAll('\n', ' ').replace(/\s+/g, ' ').trim()
25
+ const commandLine = command.split('\n')[0] ?? ''
26
+ const hasMoreCommand = command.trim() !== commandLine.trim()
27
+ const showCommandExpand = hasMoreCommand || commandLine.length > 80
28
+ const [showCommandDetail, setShowCommandDetail] = useState(false)
28
29
 
29
30
  return (
30
31
  <div className='tool-group bash-tool'>
31
32
  <ToolCallBox
32
- collapsible={false}
33
+ defaultExpanded={true}
34
+ type={resultItem != null ? 'result' : 'call'}
35
+ isError={resultItem?.is_error ?? false}
33
36
  header={
34
- <div className='bash-header'>
35
- <span className='material-symbols-rounded status-icon'>terminal</span>
36
- <span className='bash-title'>{t('chat.tools.bash')}</span>
37
+ <div className='bash-tool__header'>
38
+ <span className='material-symbols-rounded bash-tool__icon'>terminal</span>
39
+ <div className='bash-tool__header-main'>
40
+ <div className='bash-tool__reason-row'>
41
+ <span className='bash-tool__reason-text tool-header-hint'>
42
+ {reasonLine !== '' ? reasonLine : commandLine}
43
+ </span>
44
+ </div>
45
+ {reasonLine !== '' && (
46
+ <div className='bash-tool__command-row'>
47
+ <span
48
+ className={`bash-tool__command-text tool-header-mono${
49
+ showCommandExpand ? ' bash-tool__command-text--clickable' : ''
50
+ }`}
51
+ title={showCommandExpand ? t('chat.tools.viewCommand') : undefined}
52
+ onClick={(e) => {
53
+ if (!showCommandExpand) return
54
+ e.stopPropagation()
55
+ setShowCommandDetail(prev => !prev)
56
+ }}
57
+ >
58
+ {commandLine}
59
+ {hasMoreCommand ? ' …' : ''}
60
+ </span>
61
+ </div>
62
+ )}
63
+ </div>
64
+ <div className='bash-tool__header-tags'>
65
+ {typeof timeout === 'number' && Number.isFinite(timeout) && (
66
+ <span
67
+ className='tool-icon-tag'
68
+ title={`${t('chat.tools.timeout')}: ${timeout}ms`}
69
+ >
70
+ <span className='material-symbols-rounded tool-icon-tag__icon'>timer</span>
71
+ <span className='tool-icon-tag__text'>
72
+ {timeout % 1000 === 0 ? `${timeout / 1000}s` : `${timeout}ms`}
73
+ </span>
74
+ </span>
75
+ )}
76
+ {runInBackground === true && (
77
+ <span className='tool-icon-tag' title={t('chat.tools.runInBackground')}>
78
+ <span className='material-symbols-rounded tool-icon-tag__icon'>schedule</span>
79
+ </span>
80
+ )}
81
+ {dangerouslyDisableSandbox === true && (
82
+ <span className='tool-icon-tag' title={t('chat.tools.dangerouslyDisableSandbox')}>
83
+ <span className='material-symbols-rounded tool-icon-tag__icon'>shield_lock</span>
84
+ </span>
85
+ )}
86
+ </div>
37
87
  </div>
38
88
  }
39
89
  content={
40
90
  <div className='tool-content'>
41
- {(reason != null && reason !== '') && (
42
- <div className='tool-reason markdown-body'>
43
- <ReactMarkdown remarkPlugins={[remarkGfm]}>{reason}</ReactMarkdown>
91
+ {showCommandDetail && (
92
+ <div className='bash-tool__command-detail'>
93
+ <div className='tool-code-wrapper'>
94
+ <CodeBlock code={command} lang='shell' hideHeader={true} />
95
+ </div>
44
96
  </div>
45
97
  )}
46
- <div className='bash-content-scroll'>
47
- <div className='bash-code-wrapper'>
48
- <CodeBlock code={command} lang='shell' />
98
+ <div className='tool-scroll'>
99
+ <div className='tool-code-wrapper'>
100
+ {resultItem
101
+ ? (typeof resultItem.content === 'string'
102
+ ? <CodeBlock code={resultItem.content} lang='text' hideHeader={true} />
103
+ : <CodeBlock code={safeJsonStringify(resultItem.content, 2)} lang='json' hideHeader={true} />)
104
+ : (
105
+ <div className='tool-placeholder'>
106
+ {t('chat.result')}
107
+ </div>
108
+ )}
49
109
  </div>
50
110
  </div>
51
111
  </div>
52
112
  }
53
113
  />
54
-
55
- {resultItem != null && (
56
- <ToolCallBox
57
- type='result'
58
- isError={resultItem.is_error}
59
- header={
60
- <div className='result-header'>
61
- <span className='material-symbols-rounded status-icon'>
62
- {resultItem.is_error === true ? 'error' : 'check_circle'}
63
- </span>
64
- <span className='result-title'>{t('chat.result')}</span>
65
- </div>
66
- }
67
- content={
68
- <div className='tool-content'>
69
- <div className='bash-content-scroll'>
70
- <div className='bash-code-wrapper'>
71
- {typeof resultItem.content === 'string'
72
- ? <CodeBlock code={resultItem.content} lang='text' />
73
- : <CodeBlock code={safeJsonStringify(resultItem.content, 2)} lang='json' />}
74
- </div>
75
- </div>
76
- </div>
77
- }
78
- />
79
- )}
80
114
  </div>
81
115
  )
82
116
  })
@@ -1,83 +1,4 @@
1
1
  .glob-tool {
2
- .tool-header-content {
3
- display: flex;
4
- align-items: center;
5
- width: 100%;
6
- height: 100%;
7
- overflow: hidden;
8
-
9
- .material-symbols-rounded {
10
- font-size: 18px;
11
- display: flex;
12
- align-items: center;
13
- justify-content: center;
14
- color: var(--sub-text-color);
15
- height: 20px;
16
- width: 18px;
17
- margin-right: 8px;
18
- position: relative;
19
- top: 1px;
20
- }
21
-
22
- .command-name {
23
- font-size: 13px;
24
- font-weight: 500;
25
- color: var(--text-color);
26
- white-space: nowrap;
27
- line-height: 20px;
28
- display: flex;
29
- align-items: center;
30
- margin-right: 8px;
31
- }
32
-
33
- .pattern {
34
- font-size: 12px;
35
- color: var(--sub-text-color);
36
- white-space: nowrap;
37
- overflow: hidden;
38
- text-overflow: ellipsis;
39
- display: flex;
40
- align-items: center;
41
- min-width: 0;
42
- flex: 1;
43
- line-height: 20px;
44
- }
45
-
46
- .file-count {
47
- font-size: 12px;
48
- color: var(--sub-text-color);
49
- white-space: nowrap;
50
- margin-left: 8px;
51
- flex-shrink: 0;
52
- }
53
- }
54
-
55
- .input-details {
56
- padding: 8px 12px;
57
- font-size: 12px;
58
- color: var(--sub-text-color);
59
- border-bottom: 1px solid var(--border-color);
60
-
61
- .label {
62
- font-weight: 500;
63
- margin-right: 8px;
64
- }
65
-
66
- .value {
67
- font-family: var(--font-mono);
68
- background: var(--bg-color-hover);
69
- padding: 2px 4px;
70
- border-radius: 4px;
71
- }
72
- }
73
-
74
- .tool-placeholder {
75
- padding: 8px 12px;
76
- color: var(--sub-text-color);
77
- font-size: 12px;
78
- font-style: italic;
79
- }
80
-
81
2
  .file-list-container {
82
3
  border-radius: 0;
83
4
  border-left: none;
@@ -1,42 +1,20 @@
1
- import React, { useMemo } from 'react'
2
1
  import './GlobTool.scss'
3
- import { useTranslation } from 'react-i18next'
4
-
2
+ import React, { useMemo } from 'react'
3
+ import type { ToolInputs } from '@vibe-forge/core'
4
+ import { ToolCallBox } from '../core/ToolCallBox'
5
+ import { safeJsonStringify } from '#~/utils/safe-serialize'
5
6
  import { defineToolRender } from '../defineToolRender'
6
- import { ToolCallBox } from '../../ToolCallBox'
7
- import { safeJsonStringify } from '../../safeSerialize'
8
7
  import { FileList } from './components/FileList'
8
+ import { normalizeResultLines } from './utils'
9
9
 
10
10
  export const GlobTool = defineToolRender(({ item, resultItem }) => {
11
- const { t } = useTranslation()
12
- const input = (item.input != null ? item.input : {}) as { pattern?: string; path?: string }
11
+ const input = (item.input != null ? item.input : {}) as ToolInputs['adapter:claude-code:Glob']
13
12
  const pattern = (input.pattern != null && input.pattern !== '') ? input.pattern : '*'
14
13
  const path = input.path
15
14
 
16
15
  const fileCount = useMemo(() => {
17
16
  if (!resultItem) return null
18
- const content = resultItem.content
19
- let lines: string[] = []
20
-
21
- if (typeof content === 'string') {
22
- if (content.trim().startsWith('[') && content.trim().endsWith(']')) {
23
- try {
24
- const parsed = JSON.parse(content)
25
- if (Array.isArray(parsed)) {
26
- lines = parsed.map(String)
27
- } else {
28
- lines = content.split('\n')
29
- }
30
- } catch (e) {
31
- lines = content.split('\n')
32
- }
33
- } else {
34
- lines = content.split('\n')
35
- }
36
- } else if (Array.isArray(content)) {
37
- lines = content.map(String)
38
- }
39
-
17
+ const lines = normalizeResultLines(resultItem.content)
40
18
  const count = lines.filter(line => line.trim() !== '').length
41
19
  return count
42
20
  }, [resultItem])
@@ -46,20 +24,22 @@ export const GlobTool = defineToolRender(({ item, resultItem }) => {
46
24
  <ToolCallBox
47
25
  header={
48
26
  <div className='tool-header-content'>
49
- <span className='material-symbols-rounded'>search</span>
50
- <span className='command-name'>Glob</span>
51
- <span className='pattern'>{pattern}</span>
27
+ <span className='material-symbols-rounded tool-header-icon'>search</span>
28
+ <span className='tool-header-title'>Glob</span>
29
+ <span className='tool-header-secondary'>{pattern}</span>
52
30
  {fileCount !== null && (
53
- <span className='file-count'>({fileCount} files)</span>
31
+ <span className='tool-header-chip'>{fileCount} files</span>
54
32
  )}
55
33
  </div>
56
34
  }
57
35
  content={
58
36
  <div className='tool-content'>
59
37
  {path && (
60
- <div className='input-details'>
61
- <span className='label'>Path:</span>
62
- <span className='value'>{path}</span>
38
+ <div className='tool-input-grid'>
39
+ <div className='tool-input-item'>
40
+ <span className='tool-input-label'>Path</span>
41
+ <span className='tool-input-value'>{path}</span>
42
+ </div>
63
43
  </div>
64
44
  )}
65
45
  {resultItem
@@ -1,91 +1,4 @@
1
1
  .grep-tool {
2
- .tool-header-content {
3
- display: flex;
4
- align-items: center;
5
- width: 100%;
6
- height: 100%;
7
- overflow: hidden;
8
-
9
- .material-symbols-rounded {
10
- font-size: 18px;
11
- display: flex;
12
- align-items: center;
13
- justify-content: center;
14
- color: var(--sub-text-color);
15
- height: 20px;
16
- width: 18px;
17
- margin-right: 8px;
18
- position: relative;
19
- top: 1px;
20
- }
21
-
22
- .command-name {
23
- font-size: 13px;
24
- font-weight: 500;
25
- color: var(--text-color);
26
- white-space: nowrap;
27
- line-height: 20px;
28
- display: flex;
29
- align-items: center;
30
- margin-right: 8px;
31
- }
32
-
33
- .pattern {
34
- font-size: 12px;
35
- color: var(--sub-text-color);
36
- white-space: nowrap;
37
- overflow: hidden;
38
- text-overflow: ellipsis;
39
- display: flex;
40
- align-items: center;
41
- min-width: 0;
42
- flex: 1;
43
- line-height: 20px;
44
- }
45
-
46
- .file-count {
47
- font-size: 12px;
48
- color: var(--sub-text-color);
49
- white-space: nowrap;
50
- margin-left: 8px;
51
- flex-shrink: 0;
52
- }
53
- }
54
-
55
- .input-details-grid {
56
- display: flex;
57
- flex-wrap: wrap;
58
- gap: 12px;
59
- padding: 8px 12px;
60
- border-bottom: 1px solid var(--border-color);
61
-
62
- .input-detail-item {
63
- display: flex;
64
- align-items: center;
65
- font-size: 12px;
66
- color: var(--sub-text-color);
67
-
68
- .label {
69
- font-weight: 500;
70
- margin-right: 6px;
71
- }
72
-
73
- .value {
74
- font-family: var(--font-mono);
75
- background: var(--bg-color-hover);
76
- padding: 2px 4px;
77
- border-radius: 4px;
78
- }
79
- }
80
- }
81
-
82
- .tool-placeholder {
83
- padding: 8px 12px;
84
- color: var(--sub-text-color);
85
- font-size: 12px;
86
- font-style: italic;
87
- }
88
-
89
2
  .file-list-container {
90
3
  border-radius: 0;
91
4
  border-left: none;
@@ -1,15 +1,13 @@
1
- import React, { useMemo } from 'react'
2
1
  import './GrepTool.scss'
3
- import { useTranslation } from 'react-i18next'
4
-
2
+ import React, { useMemo } from 'react'
3
+ import { CodeBlock } from '#~/components/CodeBlock'
4
+ import { ToolCallBox } from '../core/ToolCallBox'
5
+ import { safeJsonStringify } from '#~/utils/safe-serialize'
5
6
  import { defineToolRender } from '../defineToolRender'
6
- import { CodeBlock } from '../../CodeBlock'
7
- import { ToolCallBox } from '../../ToolCallBox'
8
- import { safeJsonStringify } from '../../safeSerialize'
9
7
  import { FileList } from './components/FileList'
8
+ import { normalizeResultLines } from './utils'
10
9
 
11
10
  export const GrepTool = defineToolRender(({ item, resultItem }) => {
12
- const { t } = useTranslation()
13
11
  const input = (item.input != null ? item.input : {}) as {
14
12
  pattern?: string
15
13
  path?: string
@@ -23,28 +21,7 @@ export const GrepTool = defineToolRender(({ item, resultItem }) => {
23
21
 
24
22
  const fileCount = useMemo(() => {
25
23
  if (!resultItem) return null
26
- const content = resultItem.content
27
- let lines: string[] = []
28
-
29
- if (typeof content === 'string') {
30
- if (content.trim().startsWith('[') && content.trim().endsWith(']')) {
31
- try {
32
- const parsed = JSON.parse(content)
33
- if (Array.isArray(parsed)) {
34
- lines = parsed.map(String)
35
- } else {
36
- lines = content.split('\n')
37
- }
38
- } catch (e) {
39
- lines = content.split('\n')
40
- }
41
- } else {
42
- lines = content.split('\n')
43
- }
44
- } else if (Array.isArray(content)) {
45
- lines = content.map(String)
46
- }
47
-
24
+ const lines = normalizeResultLines(resultItem.content)
48
25
  const count = lines.filter(line => line.trim() !== '').length
49
26
  return count
50
27
  }, [resultItem])
@@ -54,30 +31,34 @@ export const GrepTool = defineToolRender(({ item, resultItem }) => {
54
31
  <ToolCallBox
55
32
  header={
56
33
  <div className='tool-header-content'>
57
- <span className='material-symbols-rounded'>find_in_page</span>
58
- <span className='command-name'>Grep</span>
59
- <span className='pattern'>{pattern}</span>
34
+ <span className='material-symbols-rounded tool-header-icon'>find_in_page</span>
35
+ <span className='tool-header-title'>Grep</span>
36
+ <span className='tool-header-secondary'>{pattern}</span>
60
37
  {fileCount !== null && (
61
- <span className='file-count'>({fileCount} matches)</span>
38
+ <span className='tool-header-chip'>{fileCount} matches</span>
62
39
  )}
63
40
  </div>
64
41
  }
65
42
  content={
66
43
  <div className='tool-content'>
67
- {(path || fileGlob) && (
68
- <div className='input-details-grid'>
44
+ {(path || fileGlob || outputMode) && (
45
+ <div className='tool-input-grid'>
69
46
  {path && (
70
- <div className='input-detail-item'>
71
- <span className='label'>Path:</span>
72
- <span className='value'>{path}</span>
47
+ <div className='tool-input-item'>
48
+ <span className='tool-input-label'>Path</span>
49
+ <span className='tool-input-value'>{path}</span>
73
50
  </div>
74
51
  )}
75
52
  {fileGlob && (
76
- <div className='input-detail-item'>
77
- <span className='label'>Glob:</span>
78
- <span className='value'>{fileGlob}</span>
53
+ <div className='tool-input-item'>
54
+ <span className='tool-input-label'>Glob</span>
55
+ <span className='tool-input-value'>{fileGlob}</span>
79
56
  </div>
80
57
  )}
58
+ <div className='tool-input-item'>
59
+ <span className='tool-input-label'>Mode</span>
60
+ <span className='tool-input-value'>{outputMode}</span>
61
+ </div>
81
62
  </div>
82
63
  )}
83
64
  {resultItem
@@ -1,83 +1,4 @@
1
1
  .ls-tool {
2
- .tool-header-content {
3
- display: flex;
4
- align-items: center;
5
- width: 100%;
6
- height: 100%;
7
- overflow: hidden;
8
-
9
- .material-symbols-rounded {
10
- font-size: 18px;
11
- display: flex;
12
- align-items: center;
13
- justify-content: center;
14
- color: var(--sub-text-color);
15
- height: 20px;
16
- width: 18px;
17
- margin-right: 8px;
18
- position: relative;
19
- top: 1px;
20
- }
21
-
22
- .command-name {
23
- font-size: 13px;
24
- font-weight: 500;
25
- color: var(--text-color);
26
- white-space: nowrap;
27
- line-height: 20px;
28
- display: flex;
29
- align-items: center;
30
- margin-right: 8px;
31
- }
32
-
33
- .path {
34
- font-size: 12px;
35
- color: var(--sub-text-color);
36
- white-space: nowrap;
37
- overflow: hidden;
38
- text-overflow: ellipsis;
39
- display: flex;
40
- align-items: center;
41
- min-width: 0;
42
- flex: 1;
43
- line-height: 20px;
44
- }
45
-
46
- .file-count {
47
- font-size: 12px;
48
- color: var(--sub-text-color);
49
- white-space: nowrap;
50
- margin-left: 8px;
51
- flex-shrink: 0;
52
- }
53
- }
54
-
55
- .input-details {
56
- padding: 8px 12px;
57
- font-size: 12px;
58
- color: var(--sub-text-color);
59
- border-bottom: 1px solid var(--border-color);
60
-
61
- .label {
62
- font-weight: 500;
63
- margin-right: 8px;
64
- }
65
-
66
- code {
67
- font-family: var(--font-mono);
68
- background: var(--bg-color-hover);
69
- padding: 2px 4px;
70
- border-radius: 4px;
71
- }
72
- }
73
-
74
- .tool-placeholder {
75
- padding: 8px 12px;
76
- color: var(--sub-text-color);
77
- font-size: 12px;
78
- font-style: italic;
79
- }
80
-
81
2
  .file-list-container {
82
3
  border-radius: 0;
83
4
  border: none;
@@ -1,16 +1,14 @@
1
- import React, { useMemo } from 'react'
2
1
  import './LsTool.scss'
3
- import { useTranslation } from 'react-i18next'
4
-
2
+ import React, { useMemo } from 'react'
3
+ import type { ToolInputs } from '@vibe-forge/core'
5
4
  import { defineToolRender } from '../defineToolRender'
6
- import { CodeBlock } from '../../CodeBlock'
7
- import { ToolCallBox } from '../../ToolCallBox'
8
- import { safeJsonStringify } from '../../safeSerialize'
5
+ import { CodeBlock } from '#~/components/CodeBlock'
6
+ import { ToolCallBox } from '../core/ToolCallBox'
7
+ import { safeJsonStringify } from '#~/utils/safe-serialize'
9
8
  import { FileList } from './components/FileList'
10
9
 
11
10
  export const LsTool = defineToolRender(({ item, resultItem }) => {
12
- const { t } = useTranslation()
13
- const input = (item.input != null ? item.input : {}) as { path?: string; ignore?: string[] }
11
+ const input = (item.input != null ? item.input : {}) as ToolInputs['adapter:claude-code:LS']
14
12
  const path = (input.path != null && input.path !== '') ? input.path : 'current directory'
15
13
  const ignore = input.ignore
16
14
 
@@ -43,20 +41,22 @@ export const LsTool = defineToolRender(({ item, resultItem }) => {
43
41
  <ToolCallBox
44
42
  header={
45
43
  <div className='tool-header-content'>
46
- <span className='material-symbols-rounded'>folder_open</span>
47
- <span className='command-name'>LS</span>
48
- <span className='path'>{path}</span>
44
+ <span className='material-symbols-rounded tool-header-icon'>folder_open</span>
45
+ <span className='tool-header-title'>LS</span>
46
+ <span className='tool-header-secondary'>{path}</span>
49
47
  {fileCount !== null && (
50
- <span className='file-count'>({fileCount} files)</span>
48
+ <span className='tool-header-chip'>{fileCount} files</span>
51
49
  )}
52
50
  </div>
53
51
  }
54
52
  content={
55
53
  <div className='tool-content'>
56
54
  {ignore && ignore.length > 0 && (
57
- <div className='input-details'>
58
- <span className='label'>Ignore:</span>
59
- <code>{JSON.stringify(ignore)}</code>
55
+ <div className='tool-input-grid'>
56
+ <div className='tool-input-item'>
57
+ <span className='tool-input-label'>Ignore</span>
58
+ <span className='tool-input-value'>{JSON.stringify(ignore)}</span>
59
+ </div>
60
60
  </div>
61
61
  )}
62
62