@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,216 @@
1
+ import React, { useEffect, useState } from 'react'
2
+ import { FaCheckCircle, FaListUl, FaBolt, FaCheck, FaChevronRight } from 'react-icons/fa'
3
+
4
+ const ProcessPanel = ({ processes = [], onDismiss, isEmbedded = false }) => {
5
+ const [renderedProcesses, setRenderedProcesses] = useState([])
6
+ const executingTaskCount = processes.filter(
7
+ (process) => process.type === 'planning' && process.status === 'active'
8
+ ).length
9
+
10
+ // Sync rendered processes with delayed unmount
11
+ useEffect(() => {
12
+ setRenderedProcesses((prev) => {
13
+ let next = prev.map((rp) => {
14
+ const updated = processes.find((p) => p.id === rp.id)
15
+ if (updated) return { ...updated, isExiting: false }
16
+ if (!rp.isExiting) return { ...rp, isExiting: true }
17
+ return rp
18
+ })
19
+
20
+ processes.forEach((p) => {
21
+ if (!prev.find((rp) => rp.id === p.id)) {
22
+ next.push({ ...p, isExiting: false })
23
+ }
24
+ })
25
+
26
+ return next
27
+ })
28
+ }, [processes])
29
+
30
+ // Clean up exiting processes after animation
31
+ useEffect(() => {
32
+ const hasExiting = renderedProcesses.some((p) => p.isExiting)
33
+ if (hasExiting) {
34
+ const timer = setTimeout(() => {
35
+ setRenderedProcesses((prev) => prev.filter((p) => !p.isExiting))
36
+ }, 250)
37
+ return () => clearTimeout(timer)
38
+ }
39
+ }, [renderedProcesses])
40
+
41
+ // Auto-dismiss logic for 'done' and 'failed' status
42
+ useEffect(() => {
43
+ const timers = []
44
+ processes.forEach((proc) => {
45
+ if (proc.status === 'done' || proc.status === 'completed' || proc.status === 'failed') {
46
+ const timeout = proc.type === 'planning' ? 1200 : 2500
47
+ const timer = setTimeout(() => {
48
+ if (onDismiss) onDismiss(proc.id)
49
+ }, timeout)
50
+ timers.push(timer)
51
+ }
52
+ })
53
+ return () => {
54
+ timers.forEach((t) => clearTimeout(t))
55
+ }
56
+ }, [processes, onDismiss])
57
+
58
+ if (!renderedProcesses || renderedProcesses.length === 0) return null
59
+
60
+ return (
61
+ <div className="w-full flex flex-col gap-2">
62
+ {renderedProcesses.map((proc) => {
63
+ if (proc.type === 'planning') {
64
+ const { steps, currentStep, reasoning } = proc.data || {}
65
+ const isDone = proc.status === 'done'
66
+ const isFailed = proc.status === 'failed'
67
+ const isPaused = proc.status === 'paused'
68
+ const executionTitle =
69
+ executingTaskCount === 1
70
+ ? 'Executing 1 Task'
71
+ : `Executing ${Math.max(executingTaskCount, 1)} Tasks`
72
+
73
+ return (
74
+ <div
75
+ key={proc.id}
76
+ className="bg-black/60 border border-primary/20 rounded-xl p-3 shadow-lg flex flex-col gap-1.5 animate-[holo-project-in_0.2s_ease-out_forwards]"
77
+ >
78
+ <div className="flex items-center justify-between border-b border-white/5 pb-1.5 text-xs font-mono font-bold">
79
+ <div className="flex items-center gap-1.5 text-primary">
80
+ {isDone ? (
81
+ <FaCheckCircle className="text-success" />
82
+ ) : isFailed ? (
83
+ <FaBolt className="text-error" />
84
+ ) : isPaused ? (
85
+ <FaBolt className="text-warning" />
86
+ ) : (
87
+ <FaListUl className="text-primary animate-pulse" />
88
+ )}
89
+ <span>{isDone ? 'Task Completed' : isFailed ? 'Task Failed' : executionTitle}</span>
90
+ </div>
91
+ {onDismiss && (
92
+ <button
93
+ onClick={() => onDismiss(proc.id)}
94
+ className="text-white/40 hover:text-white text-xs cursor-pointer px-1"
95
+ >
96
+ ✕
97
+ </button>
98
+ )}
99
+ </div>
100
+
101
+ {reasoning && (
102
+ <details className="group mt-1">
103
+ <summary className="text-[10px] cursor-pointer select-none flex items-center gap-1 opacity-50 hover:opacity-100 transition-opacity uppercase tracking-wider">
104
+ <FaChevronRight className="group-open:rotate-90 transition-transform text-[8px]" />
105
+ Proses Pemikiran
106
+ </summary>
107
+ <div className="text-[10px] opacity-70 border-l border-primary/30 pl-2 mt-1 mb-1 font-mono whitespace-pre-wrap">
108
+ {reasoning}
109
+ </div>
110
+ </details>
111
+ )}
112
+
113
+ {steps && steps.length > 0 && (
114
+ <div className="flex flex-col gap-1 mt-1">
115
+ {steps.map((step, idx) => {
116
+ let prefix = `${idx + 1}.`
117
+ let opacity = 'opacity-40 text-white/70'
118
+ let suffix = ''
119
+
120
+ if (idx < currentStep) {
121
+ prefix = <FaCheck className="inline" size={9} />
122
+ opacity = 'opacity-100 text-success font-bold'
123
+ } else if (idx === currentStep && !isDone) {
124
+ opacity = 'opacity-100 text-primary font-bold animate-pulse'
125
+ suffix = '...'
126
+ }
127
+
128
+ const hasQuery = typeof step === 'object' && step.query
129
+ const taskTitle = typeof step === 'object' ? step.task : step
130
+
131
+ return (
132
+ <div key={idx} className={`flex items-start text-[10px] font-mono ${opacity}`}>
133
+ <span className="w-3.5 shrink-0 inline-block">{prefix}</span>
134
+ <div className="flex-1 min-w-0">
135
+ {hasQuery ? (
136
+ <details className="group/step outline-none">
137
+ <summary className="cursor-pointer select-none flex items-center hover:opacity-100 outline-none list-none [&::-webkit-details-marker]:hidden transition-opacity">
138
+ <FaChevronRight className="group-open/step:rotate-90 transition-transform text-[8px] mr-1 opacity-50 shrink-0" />
139
+ <span className="truncate">{taskTitle} {suffix}</span>
140
+ </summary>
141
+ <div className="mt-1 pl-2 opacity-80 text-[9px] border-l border-primary/30 ml-1 mb-1 break-words font-mono bg-black/40 p-1.5 rounded text-primary/90 max-h-32 overflow-y-auto">
142
+ {typeof step.query === 'object' ? JSON.stringify(step.query, null, 2) : step.query}
143
+ </div>
144
+ </details>
145
+ ) : (
146
+ <div className="truncate">
147
+ {taskTitle} {suffix}
148
+ </div>
149
+ )}
150
+ </div>
151
+ </div>
152
+ )
153
+ })}
154
+ </div>
155
+ )}
156
+ </div>
157
+ )
158
+ }
159
+
160
+ if (proc.type === 'plugin-execution') {
161
+ const hasQuery = !!proc.data?.query
162
+ return (
163
+ <div
164
+ key={proc.id}
165
+ className="bg-black/60 border border-primary/20 rounded-xl p-2.5 shadow-lg text-xs font-mono text-white/80 animate-[holo-project-in_0.2s_ease-out_forwards]"
166
+ >
167
+ <div className="flex items-center justify-between mb-1">
168
+ <div className="text-primary flex items-center gap-1 text-[11px] font-bold">
169
+ <FaBolt size={10} className="animate-pulse" /> {proc.data?.action}
170
+ </div>
171
+ {onDismiss && (
172
+ <button
173
+ onClick={() => onDismiss(proc.id)}
174
+ className="text-white/40 hover:text-white text-xs cursor-pointer px-1"
175
+ >
176
+ ✕
177
+ </button>
178
+ )}
179
+ </div>
180
+ {hasQuery ? (
181
+ <details className="group/plugin outline-none">
182
+ <summary className="text-[10px] text-white/70 cursor-pointer select-none flex items-center hover:opacity-100 outline-none list-none [&::-webkit-details-marker]:hidden transition-opacity">
183
+ <FaChevronRight className="group-open/plugin:rotate-90 transition-transform text-[8px] mr-1 opacity-50 shrink-0" />
184
+ <span className="truncate">
185
+ Mengeksekusi: <span className="text-primary font-semibold">{proc.data?.action}</span>
186
+ </span>
187
+ </summary>
188
+ <div className="mt-1 pl-2 opacity-80 text-[9px] border-l border-primary/30 ml-1 mb-1 font-mono bg-black/40 p-1.5 rounded text-primary/90 max-h-28 overflow-y-auto whitespace-pre-wrap break-all">
189
+ {typeof proc.data.query === 'object'
190
+ ? JSON.stringify(proc.data.query, null, 2)
191
+ : String(proc.data.query)}
192
+ </div>
193
+ </details>
194
+ ) : (
195
+ <div className="text-[10px] text-white/70 truncate">
196
+ Mengeksekusi: <span className="text-primary">{proc.data?.action}</span>
197
+ </div>
198
+ )}
199
+ {proc.data?.result && (
200
+ <div className="mt-1 p-1.5 bg-primary/10 text-primary border border-primary/20 rounded text-[9px] font-mono whitespace-pre-wrap max-h-24 overflow-y-auto">
201
+ {typeof proc.data.result === 'object'
202
+ ? JSON.stringify(proc.data.result, null, 2)
203
+ : String(proc.data.result)}
204
+ </div>
205
+ )}
206
+ </div>
207
+ )
208
+ }
209
+
210
+ return null
211
+ })}
212
+ </div>
213
+ )
214
+ }
215
+
216
+ export default ProcessPanel
@@ -0,0 +1,149 @@
1
+ import React, { useEffect, useState } from 'react'
2
+ import { FaLightbulb } from 'react-icons/fa'
3
+ import Markdown from 'react-markdown'
4
+ import remarkGfm from 'remark-gfm'
5
+ import rehypeExternalLinks from 'rehype-external-links'
6
+ import { CodeBlock } from '../Chat/CodeBlock'
7
+ import PluginExecutionBubble from '../Chat/PluginExecutionBubble'
8
+
9
+ const ResponseArea = ({ currentResponse }) => {
10
+ const [animState, setAnimState] = useState('idle') // 'fade-out', 'fade-in', 'idle'
11
+ const [displayResponse, setDisplayResponse] = useState(currentResponse)
12
+
13
+ useEffect(() => {
14
+ if (currentResponse !== displayResponse) {
15
+ if (displayResponse) {
16
+ setAnimState('fade-out')
17
+ const timer = setTimeout(() => {
18
+ setDisplayResponse(currentResponse)
19
+ setAnimState('fade-in')
20
+ }, 150)
21
+ return () => clearTimeout(timer)
22
+ } else {
23
+ setDisplayResponse(currentResponse)
24
+ setAnimState('fade-in')
25
+ }
26
+ }
27
+ }, [currentResponse, displayResponse])
28
+
29
+ if (!displayResponse) return null
30
+
31
+ const { text, type, pluginResult } = displayResponse
32
+
33
+ const animationClass =
34
+ animState === 'fade-out'
35
+ ? 'animate-[response-fade-out_0.15s_ease-out_forwards]'
36
+ : animState === 'fade-in'
37
+ ? 'animate-[response-fade-in_0.2s_ease-out_forwards]'
38
+ : ''
39
+
40
+ const markdownComponents = {
41
+ code({ node, inline, className, children, ...props }) {
42
+ const match = /language-(\w+)/.exec(className || '')
43
+ return !inline ? (
44
+ <CodeBlock match={match} children={children} />
45
+ ) : (
46
+ <code
47
+ className={`px-1.5 py-0.5 rounded bg-white/10 text-primary font-mono text-xs ${className || ''}`}
48
+ {...props}
49
+ >
50
+ {children}
51
+ </code>
52
+ )
53
+ },
54
+ a: ({ node, ...props }) => {
55
+ let url = props.href || '#'
56
+ if (url !== '#' && !url.startsWith('http://') && !url.startsWith('https://')) {
57
+ url = 'https://' + url
58
+ }
59
+ return (
60
+ <a
61
+ {...props}
62
+ className="text-primary hover:underline"
63
+ onClick={(e) => {
64
+ e.preventDefault()
65
+ if (window.api && window.api.openExternal && url !== '#') {
66
+ window.api.openExternal(url)
67
+ }
68
+ }}
69
+ />
70
+ )
71
+ }
72
+ }
73
+
74
+ const renderContent = () => {
75
+ if (displayResponse.isThinking) {
76
+ return (
77
+ <div className="w-full">
78
+ <div className="p-4 rounded-xl bg-white/[0.03] text-left text-xs md:text-sm font-mono leading-relaxed text-white/90">
79
+ <div className="flex flex-col items-center justify-center gap-3 py-3">
80
+ <div className="relative w-8 h-8 flex items-center justify-center text-primary">
81
+ <svg
82
+ viewBox="0 0 50 50"
83
+ className="w-full h-full animate-[spin_3s_linear_infinite]"
84
+ >
85
+ <circle
86
+ cx="25"
87
+ cy="25"
88
+ r="20"
89
+ fill="none"
90
+ stroke="currentColor"
91
+ strokeWidth="2"
92
+ strokeDasharray="30 15"
93
+ className="opacity-40"
94
+ />
95
+ <circle
96
+ cx="25"
97
+ cy="25"
98
+ r="14"
99
+ fill="none"
100
+ stroke="currentColor"
101
+ strokeWidth="2"
102
+ strokeDasharray="20 10"
103
+ className="opacity-80 animate-[spin_2s_linear_infinite_reverse]"
104
+ style={{ transformOrigin: 'center' }}
105
+ />
106
+ </svg>
107
+ <FaLightbulb className="absolute animate-pulse text-primary" size={10} />
108
+ </div>
109
+ <div className="text-[10px] uppercase tracking-widest text-primary/80 font-mono">
110
+ {text !== 'Bentar, mikir dlu...' && text !== 'Memproses...'
111
+ ? text
112
+ : 'PROCESSING DATA...'}
113
+ </div>
114
+ </div>
115
+ </div>
116
+ </div>
117
+ )
118
+ }
119
+
120
+ return (
121
+ <div className="w-full">
122
+ <div className="p-3.5 rounded-xl bg-white/[0.03] text-left text-xs md:text-sm font-mono leading-relaxed text-white/90">
123
+ <Markdown
124
+ remarkPlugins={[remarkGfm]}
125
+ rehypePlugins={[[rehypeExternalLinks, { target: '_blank' }]]}
126
+ components={markdownComponents}
127
+ >
128
+ {text}
129
+ </Markdown>
130
+ </div>
131
+ </div>
132
+ )
133
+ }
134
+
135
+ return (
136
+ <div className={`w-full flex flex-col gap-3 ${animationClass}`}>
137
+ {renderContent()}
138
+
139
+ {/* Plugin Execution Result Chip */}
140
+ {pluginResult && (
141
+ <div className="w-full">
142
+ <PluginExecutionBubble pluginExecution={pluginResult} />
143
+ </div>
144
+ )}
145
+ </div>
146
+ )
147
+ }
148
+
149
+ export default React.memo(ResponseArea)
@@ -0,0 +1,59 @@
1
+ import { useEffect, useState } from 'react';
2
+ import { FaCheckCircle, FaInfoCircle, FaExclamationTriangle, FaTimesCircle } from 'react-icons/fa';
3
+
4
+ const StatusIndicator = ({ notifications }) => {
5
+ const [activeToasts, setActiveToasts] = useState([]);
6
+
7
+ useEffect(() => {
8
+ if (notifications && notifications.length > 0) {
9
+ const newNotifs = notifications.filter(n => !activeToasts.find(t => t.id === n.id));
10
+ if (newNotifs.length > 0) {
11
+ // Prepare toasts with types
12
+ const enhancedNotifs = newNotifs.map(notif => {
13
+ let alertType = 'alert-info';
14
+ let Icon = FaInfoCircle;
15
+ const typeStr = String(notif?.type || '').toLowerCase();
16
+
17
+ if (typeStr.includes('memory') || typeStr === 'plugin-done' || typeStr === 'success') {
18
+ alertType = 'alert-success';
19
+ Icon = FaCheckCircle;
20
+ } else if (typeStr === 'plugin-executing') {
21
+ alertType = 'alert-warning';
22
+ Icon = FaExclamationTriangle;
23
+ } else if (typeStr === 'error') {
24
+ alertType = 'alert-error';
25
+ Icon = FaTimesCircle;
26
+ }
27
+
28
+ return { ...notif, alertType, Icon };
29
+ });
30
+
31
+ setActiveToasts(prev => [...prev, ...enhancedNotifs]);
32
+
33
+ enhancedNotifs.forEach(notif => {
34
+ setTimeout(() => {
35
+ setActiveToasts(prev => prev.filter(t => t.id !== notif.id));
36
+ }, 3000);
37
+ });
38
+ }
39
+ }
40
+ }, [notifications]);
41
+
42
+ if (activeToasts.length === 0) return null;
43
+
44
+ return (
45
+ <div className="toast toast-top toast-end z-[9999] p-4">
46
+ {activeToasts.map(toast => (
47
+ <div
48
+ key={toast.id}
49
+ className={`alert ${toast.alertType} shadow-lg rounded-xl flex items-center gap-3 animate-fade-in`}
50
+ >
51
+ <toast.Icon className="w-5 h-5" />
52
+ <span className="text-sm font-medium pr-2">{toast.message}</span>
53
+ </div>
54
+ ))}
55
+ </div>
56
+ );
57
+ };
58
+
59
+ export default StatusIndicator;
@@ -0,0 +1,168 @@
1
+ import React, { useEffect, useState } from 'react';
2
+ import { FaCheck, FaSpinner, FaBrain } from 'react-icons/fa';
3
+
4
+ const ThoughtNeuralFlow = ({ processes }) => {
5
+ const [displayedPlan, setDisplayedPlan] = useState(null);
6
+ const [isVisible, setIsVisible] = useState(false);
7
+
8
+ useEffect(() => {
9
+ let activePlan = processes.find(p => p.type === 'planning');
10
+
11
+ if (!activePlan && processes.length > 0) {
12
+ const runningProc = processes.find(p => p.status !== 'done');
13
+ if (runningProc) {
14
+ let taskName = runningProc.type === 'web-search' ? 'Mencari Data...' :
15
+ runningProc.type === 'plugin-execution' ? 'Eksekusi Plugin...' :
16
+ 'Memproses...';
17
+ activePlan = {
18
+ status: runningProc.status,
19
+ data: {
20
+ plan: ['Analisis', taskName, 'Sintesis'],
21
+ currentStep: 1,
22
+ reasoning: 'Fast Track Execution'
23
+ }
24
+ };
25
+ }
26
+ }
27
+
28
+ if (activePlan) {
29
+ setDisplayedPlan(activePlan);
30
+ setIsVisible(true);
31
+ } else {
32
+ setIsVisible(false);
33
+ }
34
+ }, [processes]);
35
+
36
+ const plan = displayedPlan?.data?.plan || [];
37
+ const currentStep = displayedPlan?.data?.currentStep || 0;
38
+ const reasoning = displayedPlan?.data?.reasoning || '';
39
+ const isDone = displayedPlan?.status === 'done';
40
+
41
+ return (
42
+ <div
43
+ className={`absolute inset-0 z-0 pointer-events-none flex items-center justify-center transition-all duration-500 ease-out
44
+ ${isVisible ? 'opacity-100 scale-100' : 'opacity-0 scale-90'}
45
+ `}
46
+ >
47
+ {/* Reasoning text removed as per user request */}
48
+
49
+ {/* Nodes around the Orb */}
50
+ {plan.map((step, idx) => {
51
+ const isCompleted = idx < currentStep;
52
+ const isActive = idx === currentStep && !isDone;
53
+ const isPending = idx > currentStep;
54
+ const stepText = typeof step === 'object' ? step.task : step;
55
+
56
+ const totalNodes = plan.length;
57
+ const span = totalNodes > 3 ? 180 : 140; // Expand span if there are many nodes
58
+ const startAngle = -90 - (span / 2);
59
+ const stepAngle = totalNodes > 1 ? span / (totalNodes - 1) : 0;
60
+
61
+ const angleDeg = startAngle + (idx * stepAngle);
62
+ const angleRad = (angleDeg * Math.PI) / 180;
63
+
64
+ // Push nodes further away if there are many to avoid overlapping labels
65
+ // Use a zigzag pattern for radius if there are many nodes (alternating distances)
66
+ const baseRadius = totalNodes > 3 ? 170 : 150;
67
+ const radius = totalNodes > 3 ? baseRadius + (idx % 2 === 0 ? 0 : 40) : baseRadius;
68
+
69
+ const x = Math.cos(angleRad) * radius;
70
+ const y = Math.sin(angleRad) * radius;
71
+
72
+ // Holographic glass styles
73
+ let glassClass = 'from-base-content/10 to-base-content/5 border-base-content/20 text-base-content/40';
74
+ if (isCompleted) glassClass = 'from-primary/40 to-primary/10 border-primary/50 text-primary shadow-[inset_0_0_10px_oklch(var(--p)/0.2)]';
75
+ if (isActive) glassClass = 'from-secondary/50 to-secondary/20 border-secondary/60 text-secondary shadow-[inset_0_0_15px_oklch(var(--s)/0.4)] animate-pulse scale-110';
76
+
77
+ // Calculate line coordinates so they start from the surface of the Node and end at the surface of the Orb
78
+ // Node is at (x,y) relative to Orb(0,0).
79
+ // The SVG center (150,150) represents the Node.
80
+ const distance = radius;
81
+ const nodeClearance = 16; // Don't draw inside the 32px neuron cube
82
+ const orbClearance = 60; // Don't draw inside the 96px main orb
83
+
84
+ // Direction from Node to Orb is (-x, -y)
85
+ const dirX = -x / distance;
86
+ const dirY = -y / distance;
87
+
88
+ const startX = 150 + (dirX * nodeClearance);
89
+ const startY = 150 + (dirY * nodeClearance);
90
+
91
+ const endX = 150 + (dirX * (distance - orbClearance));
92
+ const endY = 150 + (dirY * (distance - orbClearance));
93
+
94
+ return (
95
+ <div
96
+ key={idx}
97
+ className="absolute flex flex-col items-center"
98
+ style={{
99
+ transform: `translate(${x}px, ${y}px)`,
100
+ transition: 'all 0.5s cubic-bezier(0.4, 0, 0.2, 1)',
101
+ transitionDelay: `${idx * 100}ms`
102
+ }}
103
+ >
104
+ {/* Draw SVG line connecting to center (Orb) */}
105
+ <svg className="absolute w-[300px] h-[300px] pointer-events-none overflow-visible" style={{ top: -150, left: -150 }}>
106
+ <line
107
+ x1={startX} y1={startY}
108
+ x2={endX} y2={endY}
109
+ stroke="currentColor"
110
+ className={isCompleted ? 'text-primary opacity-50' : isActive ? 'text-secondary opacity-80' : 'text-base-content opacity-20'}
111
+ strokeWidth="2"
112
+ strokeDasharray="4 4"
113
+ />
114
+ </svg>
115
+
116
+ {/* The Node (3D Neuron) */}
117
+ <div className="relative w-8 h-8 z-10 perspective-1000">
118
+ <div
119
+ className="w-full h-full relative"
120
+ style={{
121
+ transformStyle: 'preserve-3d',
122
+ animation: isActive ? 'neuron-spin 4s linear infinite' : 'neuron-spin 10s linear infinite'
123
+ }}
124
+ >
125
+ {['front', 'back', 'right', 'left', 'top', 'bottom'].map((face) => {
126
+ let transform = '';
127
+ // 8 = 2rem = 32px -> half is 16px
128
+ if (face === 'front') transform = 'translateZ(16px)';
129
+ if (face === 'back') transform = 'rotateY(180deg) translateZ(16px)';
130
+ if (face === 'right') transform = 'rotateY(90deg) translateZ(16px)';
131
+ if (face === 'left') transform = 'rotateY(-90deg) translateZ(16px)';
132
+ if (face === 'top') transform = 'rotateX(90deg) translateZ(16px)';
133
+ if (face === 'bottom') transform = 'rotateX(-90deg) translateZ(16px)';
134
+
135
+ return (
136
+ <div
137
+ key={face}
138
+ className={`absolute inset-0 m-auto w-full h-full rounded-[4px] border backdrop-blur-sm bg-gradient-to-br flex items-center justify-center transition-all duration-700 ease-in-out ${glassClass}`}
139
+ style={{ transform }}
140
+ >
141
+ {face === 'front' && (
142
+ <div className="relative w-4 h-4 flex items-center justify-center">
143
+ <div className={`absolute inset-0 flex items-center justify-center transition-all duration-500 ${isCompleted ? 'opacity-100 scale-100 rotate-0' : 'opacity-0 scale-50 -rotate-90'}`}>
144
+ <FaCheck size={10} />
145
+ </div>
146
+ <div className={`absolute inset-0 flex items-center justify-center transition-all duration-500 ${isActive ? 'opacity-100 scale-100' : 'opacity-0 scale-50'}`}>
147
+ <FaSpinner className="animate-spin" size={10} />
148
+ </div>
149
+ <div className={`absolute inset-0 flex items-center justify-center transition-all duration-500 ${isPending ? 'opacity-100 scale-100' : 'opacity-0 scale-50'}`}>
150
+ <span className="text-[10px]">{idx + 1}</span>
151
+ </div>
152
+ </div>
153
+ )}
154
+ </div>
155
+ );
156
+ })}
157
+ </div>
158
+ </div>
159
+
160
+ {/* Text labels removed as per user request */}
161
+ </div>
162
+ );
163
+ })}
164
+ </div>
165
+ );
166
+ };
167
+
168
+ export default ThoughtNeuralFlow;