@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,491 @@
1
+ import { useEffect, useState, useRef, memo } from 'react'
2
+ import { useChat } from '../contexts/ChatContext'
3
+ import Avatar from '../components/core/Avatar'
4
+ import InputBar from '../components/core/InputBar'
5
+ import ResponseArea from '../components/core/ResponseArea'
6
+ import StatusIndicator from '../components/core/StatusIndicator'
7
+ import FloatingMenu from '../components/core/FloatingMenu'
8
+ import ToolClustersDeck from '../components/core/ToolClustersDeck'
9
+ import { MessageSquare, Sparkles, Terminal } from 'lucide-react'
10
+ import { useNavigate } from 'react-router-dom'
11
+ import musicCoverFallback from '../assets/music-cover.png'
12
+ import { useYoutubeMusic } from '../contexts/YoutubeMusicContext'
13
+ import { useMemoryGroomer } from '../hooks/useMemoryGroomer'
14
+ import { db, setSessionWorkspace, getAllConfig } from '../api/db'
15
+
16
+ /**
17
+ * Komponen waveform bar terisolasi (direct ref style update)
18
+ * Tidak pernah memicu re-render pada MarkHome induk saat ada event intensitas audio
19
+ */
20
+ const LiveWaveformBars = memo(() => {
21
+ const barsRef = useRef([])
22
+
23
+ useEffect(() => {
24
+ const handleIntensity = (e) => {
25
+ const intensity = typeof e.detail === 'number' ? e.detail : 0
26
+ const bars = barsRef.current
27
+ if (!bars || bars.length === 0) return
28
+
29
+ for (let i = 0; i < 6; i++) {
30
+ const el = bars[i]
31
+ if (!el) continue
32
+ const mult = i % 2 === 0 ? 7 : 4
33
+ const height = Math.max(2, Math.min(10, intensity * mult + 2))
34
+ el.style.height = `${height}px`
35
+ }
36
+ }
37
+
38
+ window.addEventListener('mark-intensity', handleIntensity)
39
+ return () => window.removeEventListener('mark-intensity', handleIntensity)
40
+ }, [])
41
+
42
+ return (
43
+ <div className="flex items-center gap-0.5 h-2.5">
44
+ {Array.from({ length: 6 }).map((_, i) => (
45
+ <span
46
+ key={i}
47
+ ref={(el) => (barsRef.current[i] = el)}
48
+ className="w-0.5 bg-primary/70 rounded-full"
49
+ style={{ height: '2px' }}
50
+ />
51
+ ))}
52
+ </div>
53
+ )
54
+ })
55
+ LiveWaveformBars.displayName = 'LiveWaveformBars'
56
+
57
+ const MarkHome = () => {
58
+ const navigate = useNavigate()
59
+ const chatContext = useChat()
60
+ const {
61
+ chatData,
62
+ message,
63
+ isLoading,
64
+ isAgentBusy,
65
+ runningSessionIds = [],
66
+ isSpeak,
67
+ setIsSpeak,
68
+ handlePlanningCommand,
69
+ orbStatus,
70
+ setOrbStatus,
71
+ notifications,
72
+ activeProcesses,
73
+ dismissProcess,
74
+ inputSource,
75
+ handleStop,
76
+ isBooting,
77
+ isRecording,
78
+ isProcessing,
79
+ audioIntensity,
80
+ startRecording,
81
+ stopRecording,
82
+ toastMessage,
83
+ setCurrentActiveSessionId
84
+ } = chatContext
85
+ const { isPlaying, currentTrack } = useYoutubeMusic()
86
+ useMemoryGroomer(false)
87
+
88
+ const isMainLoading =
89
+ (runningSessionIds && runningSessionIds.map(String).includes('1')) || isLoading
90
+
91
+ const [currentResponse, setCurrentResponse] = useState(null)
92
+ const [showMusicWidget, setShowMusicWidget] = useState(false)
93
+ const [isMusicAnimatingOut, setIsMusicAnimatingOut] = useState(false)
94
+ const [workspaceRoot, setWorkspaceRoot] = useState(null)
95
+ const [bgOverlayOpacity, setBgOverlayOpacity] = useState(65)
96
+ const [thought, setThought] = useState('')
97
+
98
+ // Listener untuk event batin Thought Ticker dari Awareness Engine
99
+ useEffect(() => {
100
+ const handleThoughtEvent = (e) => {
101
+ if (e.detail?.thought) {
102
+ setThought(e.detail.thought)
103
+ }
104
+ }
105
+ window.addEventListener('mark:thought', handleThoughtEvent)
106
+ return () => window.removeEventListener('mark:thought', handleThoughtEvent)
107
+ }, [])
108
+
109
+ // Pastikan sesi aktif MarkHome selalu Main Thread (Sesi 1)
110
+ useEffect(() => {
111
+ if (typeof setCurrentActiveSessionId === 'function') {
112
+ setCurrentActiveSessionId('1')
113
+ }
114
+ }, [setCurrentActiveSessionId])
115
+
116
+ // Muat konfigurasi workspace & overlay opacity dari database
117
+ useEffect(() => {
118
+ db.sessions
119
+ .get(1)
120
+ .then((s) => {
121
+ if (s?.workspaceRoot) setWorkspaceRoot(s.workspaceRoot)
122
+ })
123
+ .catch(() => {})
124
+
125
+ getAllConfig()
126
+ .then((cfgList) => {
127
+ if (cfgList && cfgList.length > 0 && cfgList[0].bgOverlayOpacity !== undefined) {
128
+ setBgOverlayOpacity(Number(cfgList[0].bgOverlayOpacity))
129
+ }
130
+ })
131
+ .catch(() => {})
132
+
133
+ const handleConfigUpdated = (e) => {
134
+ if (e.detail?.bgOverlayOpacity !== undefined) {
135
+ setBgOverlayOpacity(Number(e.detail.bgOverlayOpacity))
136
+ }
137
+ }
138
+ const handleWorkspaceUpdated = (e) => {
139
+ if (String(e.detail?.sessionId) === '1') {
140
+ setWorkspaceRoot(e.detail?.workspaceRoot || null)
141
+ }
142
+ }
143
+ window.addEventListener('config-updated', handleConfigUpdated)
144
+ window.addEventListener('session-workspace-updated', handleWorkspaceUpdated)
145
+ return () => {
146
+ window.removeEventListener('config-updated', handleConfigUpdated)
147
+ window.removeEventListener('session-workspace-updated', handleWorkspaceUpdated)
148
+ }
149
+ }, [])
150
+
151
+ const handleSelectWorkspace = async () => {
152
+ if (window.api && window.api.selectDirectory) {
153
+ const selected = await window.api.selectDirectory()
154
+ if (selected) {
155
+ await setSessionWorkspace(1, selected)
156
+ setWorkspaceRoot(selected)
157
+ }
158
+ }
159
+ }
160
+
161
+ useEffect(() => {
162
+ let lastSpeaking = false
163
+ const handleTtsIntensity = () => {
164
+ const isSpeaking = Boolean(window.isMarkSpeaking)
165
+ if (isSpeaking !== lastSpeaking) {
166
+ lastSpeaking = isSpeaking
167
+ setOrbStatus(isSpeaking ? 'speaking' : 'idle')
168
+ }
169
+ }
170
+ window.addEventListener('mark-intensity', handleTtsIntensity)
171
+ return () => window.removeEventListener('mark-intensity', handleTtsIntensity)
172
+ }, [setOrbStatus])
173
+
174
+ // Handle music widget exit animation
175
+ useEffect(() => {
176
+ const hasTrack = isPlaying && currentTrack?.title
177
+ if (hasTrack) {
178
+ setIsMusicAnimatingOut(false)
179
+ setShowMusicWidget(true)
180
+ } else {
181
+ if (showMusicWidget) {
182
+ setIsMusicAnimatingOut(true)
183
+ const timer = setTimeout(() => {
184
+ setShowMusicWidget(false)
185
+ setIsMusicAnimatingOut(false)
186
+ }, 400)
187
+ return () => clearTimeout(timer)
188
+ }
189
+ }
190
+ }, [isPlaying, currentTrack?.title, showMusicWidget])
191
+
192
+ // Sync orb status
193
+ useEffect(() => {
194
+ if (typeof setOrbStatus !== 'function') return
195
+ if (isRecording) {
196
+ setOrbStatus('listening')
197
+ } else if (isProcessing || isMainLoading) {
198
+ setOrbStatus('thinking')
199
+ } else if (!window.isMarkSpeaking) {
200
+ setOrbStatus('idle')
201
+ }
202
+ }, [isMainLoading, chatData, isRecording, isProcessing, setOrbStatus])
203
+
204
+ // Derived currentResponse from chatData
205
+ useEffect(() => {
206
+ if (chatData && chatData.length > 0) {
207
+ const lastItem = chatData[chatData.length - 1]
208
+
209
+ if (lastItem.role === 'ai') {
210
+ if (lastItem.isThinking || lastItem.isSearching) {
211
+ setCurrentResponse({
212
+ text: lastItem.content || 'Memproses instruksi...',
213
+ type: 'short',
214
+ isThinking: true,
215
+ mood: lastItem.mood || 'neutral'
216
+ })
217
+ } else {
218
+ setCurrentResponse({
219
+ text: lastItem.content,
220
+ type:
221
+ lastItem.content?.length > 200 || lastItem.content?.includes('\n') ? 'long' : 'short',
222
+ sources: lastItem.sources || [],
223
+ youtubeData: lastItem.youtubeData,
224
+ youtubeSummary: lastItem.youtubeLink,
225
+ pluginResult: lastItem.pluginExecution,
226
+ isProactive: lastItem.isProactive,
227
+ mood: lastItem.mood
228
+ })
229
+ }
230
+ } else {
231
+ if (isMainLoading) {
232
+ setCurrentResponse({
233
+ text: 'Memproses...',
234
+ type: 'short',
235
+ isThinking: true
236
+ })
237
+ } else {
238
+ setCurrentResponse({
239
+ text: 'Halo, saya Mark. Ada yang bisa saya bantu hari ini?',
240
+ type: 'short'
241
+ })
242
+ }
243
+ }
244
+ } else {
245
+ setCurrentResponse({
246
+ text: 'Halo, saya Mark. Ada yang bisa saya bantu hari ini?',
247
+ type: 'short'
248
+ })
249
+ }
250
+ }, [chatData, isMainLoading, isSpeak])
251
+
252
+ const handleSubmit = (e, text, opts = {}) => {
253
+ if (typeof chatContext?.handleSubmit === 'function') {
254
+ chatContext.handleSubmit(e, text, opts)
255
+ } else {
256
+ const sendText = typeof text === 'string' && text.trim() ? text.trim() : message.trim()
257
+ if (sendText && typeof handlePlanningCommand === 'function') {
258
+ handlePlanningCommand(sendText, null, false, opts)
259
+ }
260
+ }
261
+ }
262
+
263
+ const mood = currentResponse?.mood || 'neutral'
264
+
265
+ const handleAvatarInteract = (type, detail = {}) => {
266
+ // Dispatch event untuk sistem pertumbuhan relasi 4D
267
+ window.dispatchEvent(
268
+ new CustomEvent('mark-tactile-interaction', {
269
+ detail: { type, ...detail }
270
+ })
271
+ )
272
+ }
273
+
274
+ // Sinkronisasi status operasional AI secara komprehensif
275
+ const computedAvatarStatus = isRecording
276
+ ? 'listening'
277
+ : isSpeak || window.isMarkSpeaking
278
+ ? 'speaking'
279
+ : isMainLoading
280
+ ? 'thinking'
281
+ : isProcessing
282
+ ? 'processing'
283
+ : isPlaying
284
+ ? 'music_groove'
285
+ : orbStatus || 'idle'
286
+
287
+ return (
288
+ <div className="h-screen w-screen text-white overflow-hidden relative bg-[#060a08]">
289
+ {/* ── 1. BACKGROUND: Clean Minimalist Deep Dark (#060a08) ── */}
290
+
291
+ {/* ── 2. LAYER 2: Dynamic Background Overlay Tint ── */}
292
+ <div
293
+ className="absolute inset-0 z-5 pointer-events-none transition-colors duration-300"
294
+ style={{
295
+ backgroundColor: `rgba(6, 10, 8, ${bgOverlayOpacity / 100})`
296
+ }}
297
+ />
298
+
299
+ {isBooting && (
300
+ <div className="fixed inset-0 bg-base-300 flex flex-col items-center justify-center gap-5 z-[999]">
301
+ <span className="loading loading-infinity w-16 text-primary"></span>
302
+ <p className="text-sm font-semibold tracking-[0.2em] text-white/40 uppercase animate-pulse">
303
+ Membangunkan Mark...
304
+ </p>
305
+ </div>
306
+ )}
307
+
308
+ {/* ── 3. TOP BAR HUD (Sleek, Clean, No Overlapping) ── */}
309
+ <header className="absolute top-0 inset-x-0 h-14 px-6 z-40 flex items-center justify-between">
310
+ {/* Left: Menu & Studio */}
311
+ <div className="flex items-center gap-2.5">
312
+ <FloatingMenu />
313
+ <button
314
+ onClick={() => navigate('/chat')}
315
+ className="h-8 px-3 bg-white/5 hover:bg-white/10 border border-white/5 flex items-center gap-2 transition-all text-white/80 hover:text-white rounded-xl cursor-pointer text-xs font-mono font-semibold relative"
316
+ title="Buka Chat Studio"
317
+ >
318
+ <MessageSquare className="w-3.5 h-3.5 text-primary" />
319
+ <span className="hidden md:inline">Studio</span>
320
+ {isAgentBusy && !isMainLoading && (
321
+ <span className="relative flex h-2 w-2">
322
+ <span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-warning opacity-75"></span>
323
+ <span className="relative inline-flex rounded-full h-2 w-2 bg-warning"></span>
324
+ </span>
325
+ )}
326
+ </button>
327
+ </div>
328
+ </header>
329
+
330
+ {/* Global Notifications & Telemetry Popups */}
331
+ <StatusIndicator notifications={notifications} />
332
+
333
+ {toastMessage && (
334
+ <div className="absolute top-16 left-1/2 -translate-x-1/2 bg-error/90 text-white px-4 py-2 rounded-xl z-50 backdrop-blur shadow-lg text-xs font-mono">
335
+ {toastMessage}
336
+ </div>
337
+ )}
338
+
339
+ {/* ── 4. CENTER AVATAR (2.5D Cyber-Droid Companion) ── */}
340
+ <div className="absolute top-[60%] left-1/2 -translate-x-1/2 -translate-y-1/2 z-10 flex flex-col items-center justify-center pointer-events-none select-none">
341
+ <div className="scale-115 md:scale-140 lg:scale-165 xl:scale-180 pointer-events-auto cursor-pointer transition-transform duration-300">
342
+ <Avatar
343
+ status={computedAvatarStatus}
344
+ intensity={audioIntensity}
345
+ mood={mood}
346
+ onInteract={handleAvatarInteract}
347
+ />
348
+ </div>
349
+ </div>
350
+
351
+ {/* ── 5. LEFT PANEL: TOOL CLUSTER DECK (Docked Left, In-Place Process Panel & Plugins) ── */}
352
+ <ToolClustersDeck activeProcesses={activeProcesses} dismissProcess={dismissProcess} />
353
+
354
+ {/* ── 6. RIGHT PANEL: ACTIVE STREAM FEED (Docked Right, Clean Minimalist Glass) ── */}
355
+ <aside className="absolute right-6 top-18 bottom-24 w-80 lg:w-92 z-20 flex flex-col gap-2.5 pointer-events-auto">
356
+ <div className="flex-1 bg-black/40 backdrop-blur-xl border border-white/5 rounded-2xl p-3.5 shadow-2xl flex flex-col min-h-0 overflow-hidden">
357
+ {/* Header */}
358
+ <div className="flex flex-col gap-2 pb-2 mb-2 border-b border-white/5">
359
+ <div className="flex items-center justify-between">
360
+ <div className="flex items-center gap-2">
361
+ <Terminal className="w-3.5 h-3.5 text-primary" />
362
+ <h3 className="text-xs font-bold font-mono tracking-wider text-white uppercase">
363
+ LIVE RESPONSE
364
+ </h3>
365
+ </div>
366
+ <span className="text-[10px] font-mono text-primary uppercase">
367
+ {isMainLoading ? 'Streaming' : 'Ready'}
368
+ </span>
369
+ </div>
370
+
371
+ {/* Voice / Intent Telemetry Bar */}
372
+ <div className="flex items-center justify-between bg-black/40 border border-white/5 px-2.5 py-1 rounded-lg">
373
+ <div className="flex items-center gap-2">
374
+ <span
375
+ className={`w-1.5 h-1.5 rounded-full ${
376
+ isRecording
377
+ ? 'bg-error animate-ping'
378
+ : orbStatus === 'speaking'
379
+ ? 'bg-secondary animate-pulse'
380
+ : isProcessing
381
+ ? 'bg-warning animate-spin'
382
+ : 'bg-primary'
383
+ }`}
384
+ />
385
+ <span className="text-[9px] font-mono tracking-wider uppercase text-white/70">
386
+ {orbStatus === 'speaking'
387
+ ? 'TRANSMITTING'
388
+ : isRecording
389
+ ? 'LISTENING MIC'
390
+ : isProcessing
391
+ ? 'PROCESSING'
392
+ : 'STANDBY'}
393
+ </span>
394
+ </div>
395
+
396
+ {/* Audio Waveform */}
397
+ <LiveWaveformBars />
398
+ </div>
399
+ </div>
400
+
401
+ {/* Stream Response Area */}
402
+ <div className="flex-1 overflow-y-auto no-scrollbar flex flex-col justify-start">
403
+ {currentResponse ? (
404
+ <ResponseArea currentResponse={currentResponse} />
405
+ ) : (
406
+ <div className="h-full flex flex-col items-center justify-center text-center p-6 text-white/30 font-mono text-xs">
407
+ <Sparkles className="w-5 h-5 mb-2 opacity-30 text-primary" />
408
+ <p>Belum ada respons aktif.</p>
409
+ </div>
410
+ )}
411
+ </div>
412
+
413
+ {/* Now Playing Widget */}
414
+ {showMusicWidget && (
415
+ <div
416
+ className={`mt-2 bg-black/60 border border-white/5 rounded-xl p-2.5 flex items-center gap-3 ${
417
+ isMusicAnimatingOut
418
+ ? 'animate-[holo-dismiss_0.3s_ease-in_forwards]'
419
+ : 'animate-[holo-project-in_0.3s_ease-out_forwards]'
420
+ }`}
421
+ >
422
+ <div className="relative w-10 h-10 rounded-lg overflow-hidden border border-white/5 shrink-0">
423
+ {currentTrack?.thumbnail ? (
424
+ <img
425
+ src={currentTrack.thumbnail}
426
+ alt="Album Art"
427
+ className="w-full h-full object-cover"
428
+ onError={(e) => {
429
+ e.target.onerror = null
430
+ e.target.src = musicCoverFallback
431
+ }}
432
+ />
433
+ ) : (
434
+ <img
435
+ src={musicCoverFallback}
436
+ alt="Default Album Art"
437
+ className="w-full h-full object-cover"
438
+ />
439
+ )}
440
+ </div>
441
+ <div className="flex flex-col min-w-0 pr-1">
442
+ <span className="text-[8px] font-mono uppercase tracking-wider text-primary font-bold">
443
+ NOW PLAYING
444
+ </span>
445
+ <h4 className="text-xs font-bold font-mono text-white truncate max-w-50">
446
+ {currentTrack?.title}
447
+ </h4>
448
+ <p className="text-[10px] font-mono text-white/40 truncate max-w-50">
449
+ {currentTrack?.artist}
450
+ </p>
451
+ </div>
452
+ </div>
453
+ )}
454
+ </div>
455
+ </aside>
456
+
457
+ {/* ── 7. BOTTOM DOCKED INPUT BAR & SIMPLE THOUGHT TICKER ── */}
458
+ <footer className="absolute inset-x-0 bottom-0 z-40 pointer-events-auto flex flex-col items-center">
459
+ {thought && (
460
+ <div className="w-full max-w-2xl px-4 pb-1 flex items-center justify-center gap-2 pointer-events-none select-none transition-opacity duration-500 animate-[fade-in_0.3s_ease-out]">
461
+ <span className="w-1.5 h-1.5 rounded-full bg-primary/70 animate-pulse shrink-0" />
462
+ <span className="text-[11px] font-mono italic text-white/45 truncate max-w-lg">
463
+ {thought}
464
+ </span>
465
+ </div>
466
+ )}
467
+ <div className="w-full">
468
+ <InputBar
469
+ sessionId="1"
470
+ onSubmit={(prompt, sendOptions = {}) => {
471
+ setIsSpeak(false)
472
+ handleSubmit(null, prompt, sendOptions)
473
+ }}
474
+ isLoading={isMainLoading}
475
+ isRecording={isRecording}
476
+ isProcessing={isProcessing}
477
+ audioIntensity={audioIntensity}
478
+ onStartRecord={startRecording}
479
+ onStopRecord={stopRecording}
480
+ onStop={() => handleStop(1)}
481
+ source={inputSource}
482
+ workspaceRoot={workspaceRoot}
483
+ onSelectWorkspace={handleSelectWorkspace}
484
+ />
485
+ </div>
486
+ </footer>
487
+ </div>
488
+ )
489
+ }
490
+
491
+ export default MarkHome