@mazees/mark 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (227) hide show
  1. package/LICENSE +29 -0
  2. package/README.md +209 -0
  3. package/bin/mark.js +27 -0
  4. package/out/renderer/assets/icon-DHo2CYph.svg +1 -0
  5. package/out/renderer/assets/index-G2fADWO-.js +4768 -0
  6. package/out/renderer/assets/index-f3mVse3c.css +1 -0
  7. package/out/renderer/assets/music-cover-CG4vi3kZ.png +0 -0
  8. package/out/renderer/assets/poppins-devanagari-400-normal-CJDn6rn8.woff2 +0 -0
  9. package/out/renderer/assets/poppins-devanagari-400-normal-CqVvlrh5.woff +0 -0
  10. package/out/renderer/assets/poppins-devanagari-500-normal-BIdkeU1p.woff2 +0 -0
  11. package/out/renderer/assets/poppins-devanagari-500-normal-DMPDjHtT.woff +0 -0
  12. package/out/renderer/assets/poppins-devanagari-600-normal-ClASKHrr.woff +0 -0
  13. package/out/renderer/assets/poppins-devanagari-600-normal-STEjXBNN.woff2 +0 -0
  14. package/out/renderer/assets/poppins-devanagari-700-normal-O-jipLrW.woff2 +0 -0
  15. package/out/renderer/assets/poppins-devanagari-700-normal-fHs-vx92.woff +0 -0
  16. package/out/renderer/assets/poppins-latin-400-normal-BOb3E3N0.woff +0 -0
  17. package/out/renderer/assets/poppins-latin-400-normal-cpxAROuN.woff2 +0 -0
  18. package/out/renderer/assets/poppins-latin-500-normal-C8OXljZJ.woff2 +0 -0
  19. package/out/renderer/assets/poppins-latin-500-normal-DGXqpDMm.woff +0 -0
  20. package/out/renderer/assets/poppins-latin-600-normal-BJdTmd5m.woff +0 -0
  21. package/out/renderer/assets/poppins-latin-600-normal-zEkxB9Mr.woff2 +0 -0
  22. package/out/renderer/assets/poppins-latin-700-normal-BVuQR_eA.woff +0 -0
  23. package/out/renderer/assets/poppins-latin-700-normal-Qrb0O0WB.woff2 +0 -0
  24. package/out/renderer/assets/poppins-latin-ext-400-normal-DaBSavcJ.woff +0 -0
  25. package/out/renderer/assets/poppins-latin-ext-400-normal-by3JarPu.woff2 +0 -0
  26. package/out/renderer/assets/poppins-latin-ext-500-normal-CK-6C4Hw.woff2 +0 -0
  27. package/out/renderer/assets/poppins-latin-ext-500-normal-CgAe2rWW.woff +0 -0
  28. package/out/renderer/assets/poppins-latin-ext-600-normal-CAhIAdZj.woff2 +0 -0
  29. package/out/renderer/assets/poppins-latin-ext-600-normal-Df5ffKXP.woff +0 -0
  30. package/out/renderer/assets/poppins-latin-ext-700-normal-DctTR6Tg.woff +0 -0
  31. package/out/renderer/assets/poppins-latin-ext-700-normal-cby-RkWa.woff2 +0 -0
  32. package/out/renderer/favicon.ico +0 -0
  33. package/out/renderer/icon-256.png +0 -0
  34. package/out/renderer/icon.svg +1 -0
  35. package/out/renderer/index.html +25 -0
  36. package/out/renderer/manifest.json +25 -0
  37. package/out/renderer/robot-simulator.html +1640 -0
  38. package/package.json +106 -0
  39. package/src/cli/index.js +332 -0
  40. package/src/cli/monitor.js +413 -0
  41. package/src/cli/theme.js +347 -0
  42. package/src/launcher/MarkTray.cs +227 -0
  43. package/src/main/browser-agent.js +1132 -0
  44. package/src/main/git-service.js +90 -0
  45. package/src/main/google/google-calendar.js +69 -0
  46. package/src/main/google/google-drive.js +263 -0
  47. package/src/main/google/google-gmail.js +131 -0
  48. package/src/main/google/google-service.js +241 -0
  49. package/src/main/node-tools.js +23 -0
  50. package/src/main/pc-agent-scripts/mouse-locker.ps1 +76 -0
  51. package/src/main/pc-agent-scripts/ocr-region.ps1 +185 -0
  52. package/src/main/pc-agent-scripts/pc-daemon.ps1 +726 -0
  53. package/src/main/pc-agent-scripts/pc-overlay.ps1 +253 -0
  54. package/src/main/pc-agent-scripts/pick-folder.ps1 +33 -0
  55. package/src/main/pc-agent-scripts/read-ui.ps1 +181 -0
  56. package/src/main/pc-agent-scripts/take-screenshot.ps1 +24 -0
  57. package/src/main/pc-agent-scripts/win-action.ps1 +380 -0
  58. package/src/main/plugins/plugin-loader.js +306 -0
  59. package/src/main/skills/skill-manager.js +265 -0
  60. package/src/main/syntax-validator.js +455 -0
  61. package/src/main/task-daemon.js +117 -0
  62. package/src/main/telegram/telegram-service.js +835 -0
  63. package/src/main/tools/browser-tools.js +516 -0
  64. package/src/main/tools/file-tools.js +1126 -0
  65. package/src/main/tools/git-tools.js +79 -0
  66. package/src/main/tools/google-tools.js +566 -0
  67. package/src/main/tools/index.js +36 -0
  68. package/src/main/tools/media-tools.js +42 -0
  69. package/src/main/tools/system-tools.js +295 -0
  70. package/src/main/tools/task-tools.js +73 -0
  71. package/src/main/tools/telegram-tools.js +101 -0
  72. package/src/renderer/index.html +24 -0
  73. package/src/renderer/public/favicon.ico +0 -0
  74. package/src/renderer/public/icon-256.png +0 -0
  75. package/src/renderer/public/icon.svg +1 -0
  76. package/src/renderer/public/manifest.json +25 -0
  77. package/src/renderer/public/robot-simulator.html +1640 -0
  78. package/src/renderer/src/App.jsx +304 -0
  79. package/src/renderer/src/api/ai/awareness.js +294 -0
  80. package/src/renderer/src/api/ai/chatSummarizer.js +79 -0
  81. package/src/renderer/src/api/ai/contextCompactor.js +129 -0
  82. package/src/renderer/src/api/ai/contextManager.js +1130 -0
  83. package/src/renderer/src/api/ai/core.js +167 -0
  84. package/src/renderer/src/api/ai/index.js +4 -0
  85. package/src/renderer/src/api/ai/memoryGroomer.js +101 -0
  86. package/src/renderer/src/api/ai/persona.js +115 -0
  87. package/src/renderer/src/api/ai/planning.js +317 -0
  88. package/src/renderer/src/api/ai/relationship.js +177 -0
  89. package/src/renderer/src/api/ai/skillSynthesizer.js +168 -0
  90. package/src/renderer/src/api/ai/tools.js +167 -0
  91. package/src/renderer/src/api/ai/utils.js +359 -0
  92. package/src/renderer/src/api/db.js +1013 -0
  93. package/src/renderer/src/api/oramaStore.js +592 -0
  94. package/src/renderer/src/api/ragPipeline.js +87 -0
  95. package/src/renderer/src/api/subagent/subagentExecutor.js +780 -0
  96. package/src/renderer/src/api/subagent/subagentPrompt.js +44 -0
  97. package/src/renderer/src/api/subagent/subagentStore.js +173 -0
  98. package/src/renderer/src/api/taskExecutor.js +18 -0
  99. package/src/renderer/src/api/taskStore.js +315 -0
  100. package/src/renderer/src/api/tools/core-tools.js +707 -0
  101. package/src/renderer/src/api/tools/index.js +151 -0
  102. package/src/renderer/src/api/turnPairMigrator.js +200 -0
  103. package/src/renderer/src/api/vectorMemory.js +136 -0
  104. package/src/renderer/src/api/wakeWord.js +101 -0
  105. package/src/renderer/src/api/web-bridge.js +885 -0
  106. package/src/renderer/src/api/webSpeech.js +178 -0
  107. package/src/renderer/src/api/workspaceRag.js +76 -0
  108. package/src/renderer/src/assets/electron.svg +10 -0
  109. package/src/renderer/src/assets/icon.svg +1 -0
  110. package/src/renderer/src/assets/main.css +589 -0
  111. package/src/renderer/src/assets/music-cover.png +0 -0
  112. package/src/renderer/src/assets/wavy-lines.svg +25 -0
  113. package/src/renderer/src/components/Chat/ApprovalBubble.jsx +127 -0
  114. package/src/renderer/src/components/Chat/CodeBlock.jsx +83 -0
  115. package/src/renderer/src/components/Chat/DurableTaskBubble.jsx +455 -0
  116. package/src/renderer/src/components/Chat/FileDiffModal.jsx +328 -0
  117. package/src/renderer/src/components/Chat/GeminiWidgets.jsx +82 -0
  118. package/src/renderer/src/components/Chat/MemoryFooterBubble.jsx +34 -0
  119. package/src/renderer/src/components/Chat/MessageBubble.jsx +459 -0
  120. package/src/renderer/src/components/Chat/PluginExecutionBubble.jsx +41 -0
  121. package/src/renderer/src/components/Chat/ThinkingBubble.jsx +316 -0
  122. package/src/renderer/src/components/Chat/YoutubeSearchBubble.jsx +43 -0
  123. package/src/renderer/src/components/Chat/YoutubeSummaryBubble.jsx +40 -0
  124. package/src/renderer/src/components/Chat/index.js +11 -0
  125. package/src/renderer/src/components/ChatList.jsx +434 -0
  126. package/src/renderer/src/components/GlobalCameraManager.jsx +67 -0
  127. package/src/renderer/src/components/Versions.jsx +15 -0
  128. package/src/renderer/src/components/YoutubeMusicPlayer.jsx +375 -0
  129. package/src/renderer/src/components/camera/CameraPreview.jsx +236 -0
  130. package/src/renderer/src/components/config/AiEngineSection.jsx +363 -0
  131. package/src/renderer/src/components/config/CameraSection.jsx +100 -0
  132. package/src/renderer/src/components/config/PermissionsSection.jsx +130 -0
  133. package/src/renderer/src/components/config/ShortcutSection.jsx +102 -0
  134. package/src/renderer/src/components/config/VoiceSection.jsx +110 -0
  135. package/src/renderer/src/components/config/index.js +5 -0
  136. package/src/renderer/src/components/core/Avatar.jsx +2197 -0
  137. package/src/renderer/src/components/core/ConfirmModal.jsx +80 -0
  138. package/src/renderer/src/components/core/DraggableHoloCard.jsx +125 -0
  139. package/src/renderer/src/components/core/FloatingMenu.jsx +272 -0
  140. package/src/renderer/src/components/core/HoloCard.jsx +64 -0
  141. package/src/renderer/src/components/core/InputBar.jsx +1346 -0
  142. package/src/renderer/src/components/core/ProcessPanel.jsx +216 -0
  143. package/src/renderer/src/components/core/ResponseArea.jsx +149 -0
  144. package/src/renderer/src/components/core/StatusIndicator.jsx +59 -0
  145. package/src/renderer/src/components/core/ThoughtNeuralFlow.jsx +168 -0
  146. package/src/renderer/src/components/core/ToolClustersDeck.jsx +210 -0
  147. package/src/renderer/src/components/core/native-skills.js +43 -0
  148. package/src/renderer/src/components/neural-core/EmotionalCortexLobe.jsx +359 -0
  149. package/src/renderer/src/components/neural-core/NodeDissectionModal.jsx +57 -0
  150. package/src/renderer/src/components/neural-core/ProceduralMatrixLobe.jsx +193 -0
  151. package/src/renderer/src/components/neural-core/ProceduralSkillModal.jsx +53 -0
  152. package/src/renderer/src/components/neural-core/ResetAiModal.jsx +198 -0
  153. package/src/renderer/src/components/neural-core/SynapticMemoryLobe.jsx +204 -0
  154. package/src/renderer/src/components/neural-core/traitMeta.js +102 -0
  155. package/src/renderer/src/components/subagent/AgentChatFeed.jsx +603 -0
  156. package/src/renderer/src/components/subagent/AgentInspector.jsx +224 -0
  157. package/src/renderer/src/components/subagent/AgentSidebar.jsx +216 -0
  158. package/src/renderer/src/components/subagent/SubagentIntercom.jsx +572 -0
  159. package/src/renderer/src/components/subagent/SubagentTopologyMap.jsx +423 -0
  160. package/src/renderer/src/contexts/ApprovalContext.jsx +425 -0
  161. package/src/renderer/src/contexts/ChatContext.jsx +61 -0
  162. package/src/renderer/src/contexts/YoutubeMusicContext.jsx +333 -0
  163. package/src/renderer/src/data/faqData.js +202 -0
  164. package/src/renderer/src/hooks/agent/executeAgentTool.js +895 -0
  165. package/src/renderer/src/hooks/agent/index.js +4 -0
  166. package/src/renderer/src/hooks/agent/useMarkMusic.js +75 -0
  167. package/src/renderer/src/hooks/agent/useMarkPlan.js +2739 -0
  168. package/src/renderer/src/hooks/agent/useMarkState.js +173 -0
  169. package/src/renderer/src/hooks/agent/useMarkYoutube.js +82 -0
  170. package/src/renderer/src/hooks/agent/useRelationalGrowth.js +201 -0
  171. package/src/renderer/src/hooks/telegram/useTelegramBot.js +63 -0
  172. package/src/renderer/src/hooks/useAwareness.js +289 -0
  173. package/src/renderer/src/hooks/useChatArchiver.js +52 -0
  174. package/src/renderer/src/hooks/useConfirm.jsx +68 -0
  175. package/src/renderer/src/hooks/useMarkAgent.js +454 -0
  176. package/src/renderer/src/hooks/useMemoryGroomer.js +152 -0
  177. package/src/renderer/src/hooks/useVAD.js +511 -0
  178. package/src/renderer/src/hooks/useWebSpeechWakeWord.js +122 -0
  179. package/src/renderer/src/main.jsx +12 -0
  180. package/src/renderer/src/pages/ChatStudio.jsx +922 -0
  181. package/src/renderer/src/pages/Configuration.jsx +360 -0
  182. package/src/renderer/src/pages/GoogleWorkspace.jsx +293 -0
  183. package/src/renderer/src/pages/Guidebook.jsx +917 -0
  184. package/src/renderer/src/pages/Knowledge.jsx +241 -0
  185. package/src/renderer/src/pages/MarkHome.jsx +491 -0
  186. package/src/renderer/src/pages/NeuralCore.jsx +786 -0
  187. package/src/renderer/src/pages/Plugins.jsx +630 -0
  188. package/src/renderer/src/pages/SkillEditor.jsx +380 -0
  189. package/src/renderer/src/pages/Skills.jsx +219 -0
  190. package/src/renderer/src/pages/Subagents.jsx +342 -0
  191. package/src/renderer/src/pages/TelegramBot.jsx +343 -0
  192. package/src/renderer/src/utils/chatContentParser.js +203 -0
  193. package/src/renderer/src/utils/toolClusters.js +201 -0
  194. package/src/server/bin/sha3_wasm_bg.wasm +0 -0
  195. package/src/server/config-manager.js +57 -0
  196. package/src/server/index.js +195 -0
  197. package/src/server/launcher.js +87 -0
  198. package/src/server/memory/db-store.js +758 -0
  199. package/src/server/memory/orama-store.js +177 -0
  200. package/src/server/memory/vector-engine.js +109 -0
  201. package/src/server/routes/ai.routes.js +280 -0
  202. package/src/server/routes/awareness.routes.js +62 -0
  203. package/src/server/routes/chat.routes.js +61 -0
  204. package/src/server/routes/config.routes.js +41 -0
  205. package/src/server/routes/index.js +35 -0
  206. package/src/server/routes/integrations.routes.js +116 -0
  207. package/src/server/routes/memory.routes.js +256 -0
  208. package/src/server/routes/plugins.routes.js +72 -0
  209. package/src/server/routes/skills.routes.js +139 -0
  210. package/src/server/routes/subagents.routes.js +70 -0
  211. package/src/server/routes/tasks.routes.js +175 -0
  212. package/src/server/routes/workspace.routes.js +127 -0
  213. package/src/server/services/ai/ai-utils.js +161 -0
  214. package/src/server/services/ai/openai-provider.js +757 -0
  215. package/src/server/services/ai/web-provider.js +729 -0
  216. package/src/server/services/ai-bridge.js +46 -0
  217. package/src/server/services/deepseek-web.js +956 -0
  218. package/src/server/services/gemini-web.js +170 -0
  219. package/src/server/services/notification-service.js +91 -0
  220. package/src/server/services/updater.js +125 -0
  221. package/src/server/tools/awareness-tracker.js +292 -0
  222. package/src/server/tools/group-tools.js +1164 -0
  223. package/src/server/tools/media-tools.js +244 -0
  224. package/src/server/tools/pc-agent.js +327 -0
  225. package/src/server/tools/screen-service.js +51 -0
  226. package/src/server/ws-hub.js +168 -0
  227. package/src/shared/parsers/mark-tag-parser.js +275 -0
@@ -0,0 +1,316 @@
1
+ /* eslint-disable react/prop-types */
2
+ import Markdown from 'react-markdown'
3
+ import remarkGfm from 'remark-gfm'
4
+ import { Check, XCircle, Ban, Music, Brain, ChevronRight, Terminal, Loader2 } from 'lucide-react'
5
+ import { FaYoutube } from 'react-icons/fa'
6
+ import { useApproval } from '../../contexts/ApprovalContext'
7
+ import { ApprovalBubble } from './ApprovalBubble'
8
+
9
+ export const ThinkingBubble = ({
10
+ isSummarizing = false,
11
+ isSearchingMusic = false,
12
+ content = '',
13
+ reasoning = null,
14
+ executionSteps = null,
15
+ executedTools = []
16
+ }) => {
17
+ const { activeApproval } = useApproval()
18
+ const steps = executionSteps || executedTools || []
19
+ const executingStepCount = steps.length
20
+
21
+ return (
22
+ <div className="flex flex-col gap-2.5 py-1 text-sm select-text">
23
+ {/* Loading Status Header with Tech Radar (ResponseArea style) */}
24
+ <div className="flex items-center gap-2.5">
25
+ {isSummarizing ? (
26
+ <div className="flex items-center gap-2 text-warning font-medium">
27
+ <FaYoutube className="w-4 h-4 animate-bounce text-error" />
28
+ <span className="text-xs">{content || 'Meringkas video YouTube...'}</span>
29
+ </div>
30
+ ) : isSearchingMusic ? (
31
+ <div className="flex items-center gap-2 text-info font-medium">
32
+ <Music className="w-4 h-4 animate-spin text-info" />
33
+ <span className="text-xs">{content || 'Mencari lagu di YouTube Music...'}</span>
34
+ </div>
35
+ ) : (
36
+ <div className="flex items-center gap-2.5 text-primary font-medium">
37
+ {/* Holographic Dual Ring Spinner (ResponseArea style) */}
38
+ <div className="relative w-4 h-4 flex items-center justify-center text-primary shrink-0">
39
+ <svg viewBox="0 0 50 50" className="w-full h-full animate-[spin_3s_linear_infinite]">
40
+ <circle
41
+ cx="25"
42
+ cy="25"
43
+ r="20"
44
+ fill="none"
45
+ stroke="currentColor"
46
+ strokeWidth="2.5"
47
+ strokeDasharray="30 15"
48
+ className="opacity-40"
49
+ />
50
+ <circle
51
+ cx="25"
52
+ cy="25"
53
+ r="13"
54
+ fill="none"
55
+ stroke="currentColor"
56
+ strokeWidth="3.5"
57
+ strokeDasharray="20 10"
58
+ className="opacity-90 animate-[spin_1.5s_linear_infinite_reverse]"
59
+ style={{ transformOrigin: 'center' }}
60
+ />
61
+ </svg>
62
+ </div>
63
+ <span className="text-xs font-semibold animate-pulse text-white/90">
64
+ {content || 'Mark sedang menganalisis & mengeksekusi...'}
65
+ </span>
66
+ </div>
67
+ )}
68
+ </div>
69
+
70
+ {/* Live Process Execution Trace (Antigravity Style) */}
71
+ {(reasoning || (steps && steps.length > 0)) && (
72
+ <div className="flex flex-col gap-1 my-1">
73
+ {/* Collapsible Reasoning Section */}
74
+ {reasoning && (
75
+ <details open className="group/details outline-none">
76
+ <summary className="text-xs font-mono cursor-pointer select-none flex items-center gap-2 text-white/70 hover:text-white py-0.5 list-none [&::-webkit-details-marker]:hidden transition-colors">
77
+ <Brain className="w-3.5 h-3.5 text-primary/80 shrink-0" />
78
+ <span className="font-medium text-white/80">Proses Pemikiran AI</span>
79
+ <ChevronRight className="w-3 h-3 group-open/details:rotate-90 transition-transform text-white/40 ml-auto shrink-0" />
80
+ </summary>
81
+ <div className="mt-1 pl-3 my-1 text-[11px] font-mono border-l-2 border-primary/30 text-white/80 leading-relaxed max-h-56 overflow-y-auto custom-scrollbar bg-base-300/30 p-2.5 rounded-lg select-text [&_p]:my-1 [&_p]:leading-relaxed [&_h1]:text-xs [&_h1]:font-bold [&_h1]:my-1.5 [&_h2]:text-[11px] [&_h2]:font-bold [&_h2]:my-1 [&_h3]:text-[11px] [&_h3]:font-bold [&_h3]:my-1 [&_ul]:my-1 [&_ul]:ml-3.5 [&_ol]:my-1 [&_ol]:ml-3.5 [&_li]:my-0.5 [&_code]:text-[10px] [&_pre]:my-1.5 [&_hr]:my-2 [&_hr]:border-white/10">
82
+ <Markdown remarkPlugins={[remarkGfm]}>
83
+ {typeof reasoning === 'string' ? reasoning : JSON.stringify(reasoning, null, 2)}
84
+ </Markdown>
85
+ </div>
86
+ </details>
87
+ )}
88
+
89
+ {/* Executed Tools Step-by-Step List */}
90
+ {steps && steps.length > 0 && (
91
+ <details open className="group/liveprocess outline-none">
92
+ <summary className="text-xs font-mono cursor-pointer select-none flex items-center gap-2 text-white/70 hover:text-white py-1 list-none [&::-webkit-details-marker]:hidden transition-colors">
93
+ <Terminal className="w-3.5 h-3.5 text-primary/80 shrink-0" />
94
+ <span className="font-semibold text-white/90">Proses</span>
95
+ <span className="text-[10px] text-white/40 font-normal">
96
+ ({executingStepCount} langkah)
97
+ </span>
98
+ <ChevronRight className="w-3.5 h-3.5 group-open/liveprocess:rotate-90 transition-transform text-white/40 ml-auto shrink-0" />
99
+ </summary>
100
+ <div className="mt-1 pl-2.5 space-y-1 border-l-2 border-white/15 ml-1.5 my-1">
101
+ {steps.map((step, idx) => {
102
+ if (step.type === 'intervention') {
103
+ const interventionText = step.text || step.content || step.task || ''
104
+ return (
105
+ <div key={idx} className="flex items-start gap-2 py-0.5 text-xs">
106
+ <span className="font-bold text-primary font-mono shrink-0 select-none">
107
+ You :
108
+ </span>
109
+ <span className="text-white/90 font-sans select-text whitespace-pre-wrap leading-relaxed">
110
+ {interventionText}
111
+ </span>
112
+ </div>
113
+ )
114
+ }
115
+
116
+ if (step.type === 'narration' || (!step.tool && step.text)) {
117
+ return (
118
+ <div
119
+ key={idx}
120
+ className="flex flex-col py-1 pl-1 pr-2 text-xs text-white/85 leading-relaxed font-sans select-text"
121
+ >
122
+ <Markdown remarkPlugins={[remarkGfm]}>{step.text}</Markdown>
123
+ </div>
124
+ )
125
+ }
126
+
127
+ const isRunning = step.status === 'running'
128
+ const isStopped = step.status === 'stopped' || step.status === 'cancelled'
129
+ const isPendingApproval = Boolean(
130
+ activeApproval &&
131
+ activeApproval.status === 'pending' &&
132
+ isRunning &&
133
+ (activeApproval.tool === step.tool || !step.tool)
134
+ )
135
+ const hasQuery =
136
+ step.query !== undefined && step.query !== null && step.query !== ''
137
+ const hasResult =
138
+ step.resultSummary !== undefined &&
139
+ step.resultSummary !== null &&
140
+ step.resultSummary !== ''
141
+ const queryString =
142
+ typeof step.query === 'string'
143
+ ? step.query
144
+ : JSON.stringify(step.query, null, 2)
145
+ const resultString =
146
+ typeof step.resultSummary === 'string'
147
+ ? step.resultSummary
148
+ : JSON.stringify(step.resultSummary, null, 2)
149
+ const isFailed =
150
+ step.status === 'failed' ||
151
+ step.status === 'error' ||
152
+ (resultString &&
153
+ (resultString.startsWith('[ERROR]') || resultString.includes(' crash:')))
154
+
155
+ const toolLabel = step.tool || step.task || 'tool'
156
+ const displayReason = step.reason || null
157
+ let shortSummary = ''
158
+ if (hasQuery) {
159
+ try {
160
+ const parsed = JSON.parse(queryString)
161
+ shortSummary =
162
+ parsed.command ||
163
+ parsed.path ||
164
+ parsed.query ||
165
+ parsed.prompt ||
166
+ parsed.skill_name ||
167
+ queryString
168
+ } catch {
169
+ shortSummary = queryString
170
+ }
171
+ }
172
+
173
+ if (!hasQuery && !hasResult) {
174
+ return (
175
+ <div key={idx} className="flex flex-col py-0.5">
176
+ <div className="flex items-center gap-2 text-xs font-mono text-white/60">
177
+ {isPendingApproval ? (
178
+ <Loader2 className="w-3.5 h-3.5 animate-spin text-warning shrink-0" />
179
+ ) : isRunning ? (
180
+ <Loader2 className="w-3.5 h-3.5 animate-spin text-primary/80 shrink-0" />
181
+ ) : isStopped ? (
182
+ <Ban className="w-3.5 h-3.5 text-warning shrink-0" />
183
+ ) : isFailed ? (
184
+ <XCircle className="w-3.5 h-3.5 text-error shrink-0" />
185
+ ) : (
186
+ <Check className="w-3.5 h-3.5 text-success/80 shrink-0" />
187
+ )}
188
+ <span className="font-semibold text-white/90">
189
+ {displayReason || toolLabel}
190
+ </span>
191
+ {isPendingApproval ? (
192
+ <span className="text-[10px] text-warning font-normal animate-pulse">
193
+ (menunggu persetujuan...)
194
+ </span>
195
+ ) : isStopped ? (
196
+ <span className="text-[10px] text-warning/80 font-normal">
197
+ (dihentikan)
198
+ </span>
199
+ ) : null}
200
+ </div>
201
+ {isPendingApproval && (
202
+ <div className="pl-3 pr-1">
203
+ <ApprovalBubble
204
+ approvalId={activeApproval.id}
205
+ tool={activeApproval.tool}
206
+ query={activeApproval.query}
207
+ message={activeApproval.message}
208
+ status={activeApproval.status}
209
+ />
210
+ </div>
211
+ )}
212
+ </div>
213
+ )
214
+ }
215
+
216
+ return (
217
+ <div key={idx} className="flex flex-col py-0.5">
218
+ <details
219
+ className="group/livetool outline-none text-xs font-mono"
220
+ open={isRunning}
221
+ >
222
+ <summary className="list-none flex items-center gap-2 cursor-pointer text-white/60 hover:text-white select-none py-0.5 transition-colors">
223
+ {isPendingApproval ? (
224
+ <Loader2 className="w-3.5 h-3.5 animate-spin text-warning shrink-0" />
225
+ ) : isRunning ? (
226
+ <Loader2 className="w-3.5 h-3.5 animate-spin text-primary/80 shrink-0" />
227
+ ) : isStopped ? (
228
+ <Ban className="w-3.5 h-3.5 text-warning shrink-0" />
229
+ ) : isFailed ? (
230
+ <XCircle className="w-3.5 h-3.5 text-error shrink-0" />
231
+ ) : (
232
+ <Check className="w-3.5 h-3.5 text-success/80 shrink-0" />
233
+ )}
234
+ <span className="font-semibold text-white/90">
235
+ {displayReason || toolLabel}
236
+ </span>
237
+ {isPendingApproval ? (
238
+ <span className="text-[10px] text-warning font-normal animate-pulse">
239
+ (menunggu persetujuan...)
240
+ </span>
241
+ ) : isStopped ? (
242
+ <span className="text-[10px] text-warning/80 font-normal">
243
+ (dihentikan)
244
+ </span>
245
+ ) : null}
246
+ {!displayReason && shortSummary && (
247
+ <span className="text-white/40 truncate max-w-md">
248
+ {String(shortSummary).slice(0, 80)}
249
+ </span>
250
+ )}
251
+ <ChevronRight className="w-3 h-3 text-white/40 transition-transform duration-150 group-open/livetool:rotate-90 ml-auto shrink-0" />
252
+ </summary>
253
+ <div className="mt-1 pl-3 my-1.5 text-[11px] font-mono border-l-2 border-white/20 text-white/80 whitespace-pre-wrap break-all max-h-56 overflow-y-auto custom-scrollbar bg-base-300/40 p-2.5 rounded-lg space-y-1.5 select-text">
254
+ {step.tool && (
255
+ <div>
256
+ <div className="text-primary/70 font-semibold mb-0.5">Tool:</div>
257
+ <div className="text-white/90 font-mono text-[11px]">{step.tool}</div>
258
+ </div>
259
+ )}
260
+ {displayReason && (
261
+ <div>
262
+ <div className="text-info/80 font-semibold mb-0.5">Tujuan:</div>
263
+ <div className="text-white/90 font-sans">{displayReason}</div>
264
+ </div>
265
+ )}
266
+ {hasQuery && (
267
+ <div>
268
+ <div className="text-primary/70 font-semibold mb-0.5">Input:</div>
269
+ <div className="text-white/90">{queryString}</div>
270
+ </div>
271
+ )}
272
+ {hasResult && (
273
+ <div>
274
+ <div className="text-success/70 font-semibold mb-0.5">Output:</div>
275
+ <div className="text-white/80">{resultString}</div>
276
+ </div>
277
+ )}
278
+ {step.preview && (
279
+ <div className="mt-2 pt-1 border-t border-white/10">
280
+ <div className="text-primary/70 font-semibold mb-1">
281
+ Pratinjau Visual:
282
+ </div>
283
+ <div className="relative group/preview rounded-lg overflow-hidden border border-white/20 bg-black/40 max-w-sm">
284
+ <img
285
+ src={step.preview}
286
+ alt="Tool Visual Output"
287
+ className="max-h-48 w-auto object-contain cursor-pointer transition-transform duration-200 group-hover/preview:scale-105"
288
+ onClick={() => window.open(step.preview, '_blank')}
289
+ />
290
+ </div>
291
+ </div>
292
+ )}
293
+ </div>
294
+ </details>
295
+ {isPendingApproval && (
296
+ <div className="pl-3 pr-1">
297
+ <ApprovalBubble
298
+ approvalId={activeApproval.id}
299
+ tool={activeApproval.tool}
300
+ query={activeApproval.query}
301
+ message={activeApproval.message}
302
+ status={activeApproval.status}
303
+ />
304
+ </div>
305
+ )}
306
+ </div>
307
+ )
308
+ })}
309
+ </div>
310
+ </details>
311
+ )}
312
+ </div>
313
+ )}
314
+ </div>
315
+ )
316
+ }
@@ -0,0 +1,43 @@
1
+ import React from 'react'
2
+
3
+ export const YoutubeSearchBubble = ({ queryYoutube, youtubeLink }) => {
4
+ return (
5
+ <>
6
+ <h1 className="text-xs font-bold mt-2 flex items-center gap-1 uppercase tracking-wider">
7
+ <svg
8
+ aria-hidden="true"
9
+ xmlns="http://www.w3.org/2000/svg"
10
+ width="1em"
11
+ height="1em"
12
+ fill="currentColor"
13
+ viewBox="0 0 24 24"
14
+ >
15
+ <path
16
+ fillRule="evenodd"
17
+ d="M21.7 8.037a4.26 4.26 0 0 0-.789-1.964 2.84 2.84 0 0 0-1.984-.839c-2.767-.2-6.926-.2-6.926-.2s-4.157 0-6.928.2a2.836 2.836 0 0 0-1.983.839 4.225 4.225 0 0 0-.79 1.965 30.146 30.146 0 0 0-.2 3.206v1.5a30.12 30.12 0 0 0 .2 3.206c.094.712.364 1.39.784 1.972.604.536 1.38.837 2.187.848 1.583.151 6.731.2 6.731.2s4.161 0 6.928-.2a2.844 2.844 0 0 0 1.985-.84 4.27 4.27 0 0 0 .787-1.965 30.12 30.12 0 0 0 .2-3.206v-1.516a30.672 30.672 0 0 0-.202-3.206Zm-11.692 6.554v-5.62l5.4 2.819-5.4 2.801Z"
18
+ clipRule="evenodd"
19
+ />
20
+ </svg>
21
+ {`Pencarian: ${queryYoutube.slice(0, 40)}`}
22
+ {queryYoutube.length > 40 ? '...' : ''}
23
+ </h1>
24
+ <div className="p-3 bg-base-300 flex flex-wrap rounded-2xl mt-2">
25
+ {youtubeLink.map((item, idx) => {
26
+ const id = typeof item === 'object' ? item.videoId : item
27
+ return (
28
+ <iframe
29
+ key={idx}
30
+ className="w-1/2 aspect-video rounded-lg"
31
+ src={`https://www.youtube.com/embed/${id}`}
32
+ title="YouTube video player"
33
+ frameBorder="0"
34
+ allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
35
+ referrerPolicy="strict-origin-when-cross-origin"
36
+ allowFullScreen
37
+ ></iframe>
38
+ )
39
+ })}
40
+ </div>
41
+ </>
42
+ )
43
+ }
@@ -0,0 +1,40 @@
1
+ import React from 'react'
2
+
3
+ export const YoutubeSummaryBubble = ({ youtubeLink }) => {
4
+ const getYouTubeID = (text) => {
5
+ const ytRegex =
6
+ /(?:https?:\/\/)?(?:www\.|m\.)?(?:youtube\.com\/watch\?v=|youtu\.be\/|youtube\.com\/embed\/|youtube\.com\/v\/|youtube\.com\/shorts\/)([a-zA-Z0-9_-]{11})/
7
+ const match = text.match(ytRegex)
8
+ return match ? match[1] : null
9
+ }
10
+
11
+ const youtubeVideoId = getYouTubeID(youtubeLink)
12
+ const youtubeEmbedUrl = youtubeVideoId ? `https://www.youtube.com/embed/${youtubeVideoId}?rel=0` : null
13
+
14
+ return (
15
+ <div className="p-3 bg-base-300 rounded-2xl my-2 space-y-3">
16
+ {youtubeEmbedUrl ? (
17
+ <iframe
18
+ className="w-full aspect-video rounded-xl"
19
+ src={youtubeEmbedUrl}
20
+ title="YouTube video player"
21
+ frameBorder="0"
22
+ allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
23
+ referrerPolicy="strict-origin-when-cross-origin"
24
+ allowFullScreen
25
+ ></iframe>
26
+ ) : (
27
+ <div className="aspect-video rounded-xl bg-base-200 flex items-center justify-center text-sm text-base-content/70 text-center px-4">
28
+ Tidak bisa memuat pemutar YouTube untuk tautan ini.
29
+ </div>
30
+ )}
31
+ <button
32
+ type="button"
33
+ onClick={() => window.api.openExternal(youtubeLink)}
34
+ className="btn btn-sm btn-neutral w-full normal-case"
35
+ >
36
+ Watch on YouTube
37
+ </button>
38
+ </div>
39
+ )
40
+ }
@@ -0,0 +1,11 @@
1
+ export * from './CodeBlock'
2
+ export * from './MessageBubble'
3
+ export * from './ThinkingBubble'
4
+ export * from './DurableTaskBubble'
5
+ export * from './MemoryFooterBubble'
6
+ export * from './PluginExecutionBubble'
7
+ export * from './YoutubeSearchBubble'
8
+ export * from './YoutubeSummaryBubble'
9
+ export * from './GeminiWidgets'
10
+ export * from './ApprovalBubble'
11
+ export * from './FileDiffModal'