@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.
- package/LICENSE +29 -0
- package/README.md +209 -0
- package/bin/mark.js +27 -0
- package/out/renderer/assets/icon-DHo2CYph.svg +1 -0
- package/out/renderer/assets/index-G2fADWO-.js +4768 -0
- package/out/renderer/assets/index-f3mVse3c.css +1 -0
- package/out/renderer/assets/music-cover-CG4vi3kZ.png +0 -0
- package/out/renderer/assets/poppins-devanagari-400-normal-CJDn6rn8.woff2 +0 -0
- package/out/renderer/assets/poppins-devanagari-400-normal-CqVvlrh5.woff +0 -0
- package/out/renderer/assets/poppins-devanagari-500-normal-BIdkeU1p.woff2 +0 -0
- package/out/renderer/assets/poppins-devanagari-500-normal-DMPDjHtT.woff +0 -0
- package/out/renderer/assets/poppins-devanagari-600-normal-ClASKHrr.woff +0 -0
- package/out/renderer/assets/poppins-devanagari-600-normal-STEjXBNN.woff2 +0 -0
- package/out/renderer/assets/poppins-devanagari-700-normal-O-jipLrW.woff2 +0 -0
- package/out/renderer/assets/poppins-devanagari-700-normal-fHs-vx92.woff +0 -0
- package/out/renderer/assets/poppins-latin-400-normal-BOb3E3N0.woff +0 -0
- package/out/renderer/assets/poppins-latin-400-normal-cpxAROuN.woff2 +0 -0
- package/out/renderer/assets/poppins-latin-500-normal-C8OXljZJ.woff2 +0 -0
- package/out/renderer/assets/poppins-latin-500-normal-DGXqpDMm.woff +0 -0
- package/out/renderer/assets/poppins-latin-600-normal-BJdTmd5m.woff +0 -0
- package/out/renderer/assets/poppins-latin-600-normal-zEkxB9Mr.woff2 +0 -0
- package/out/renderer/assets/poppins-latin-700-normal-BVuQR_eA.woff +0 -0
- package/out/renderer/assets/poppins-latin-700-normal-Qrb0O0WB.woff2 +0 -0
- package/out/renderer/assets/poppins-latin-ext-400-normal-DaBSavcJ.woff +0 -0
- package/out/renderer/assets/poppins-latin-ext-400-normal-by3JarPu.woff2 +0 -0
- package/out/renderer/assets/poppins-latin-ext-500-normal-CK-6C4Hw.woff2 +0 -0
- package/out/renderer/assets/poppins-latin-ext-500-normal-CgAe2rWW.woff +0 -0
- package/out/renderer/assets/poppins-latin-ext-600-normal-CAhIAdZj.woff2 +0 -0
- package/out/renderer/assets/poppins-latin-ext-600-normal-Df5ffKXP.woff +0 -0
- package/out/renderer/assets/poppins-latin-ext-700-normal-DctTR6Tg.woff +0 -0
- package/out/renderer/assets/poppins-latin-ext-700-normal-cby-RkWa.woff2 +0 -0
- package/out/renderer/favicon.ico +0 -0
- package/out/renderer/icon-256.png +0 -0
- package/out/renderer/icon.svg +1 -0
- package/out/renderer/index.html +25 -0
- package/out/renderer/manifest.json +25 -0
- package/out/renderer/robot-simulator.html +1640 -0
- package/package.json +106 -0
- package/src/cli/index.js +332 -0
- package/src/cli/monitor.js +413 -0
- package/src/cli/theme.js +347 -0
- package/src/launcher/MarkTray.cs +227 -0
- package/src/main/browser-agent.js +1132 -0
- package/src/main/git-service.js +90 -0
- package/src/main/google/google-calendar.js +69 -0
- package/src/main/google/google-drive.js +263 -0
- package/src/main/google/google-gmail.js +131 -0
- package/src/main/google/google-service.js +241 -0
- package/src/main/node-tools.js +23 -0
- package/src/main/pc-agent-scripts/mouse-locker.ps1 +76 -0
- package/src/main/pc-agent-scripts/ocr-region.ps1 +185 -0
- package/src/main/pc-agent-scripts/pc-daemon.ps1 +726 -0
- package/src/main/pc-agent-scripts/pc-overlay.ps1 +253 -0
- package/src/main/pc-agent-scripts/pick-folder.ps1 +33 -0
- package/src/main/pc-agent-scripts/read-ui.ps1 +181 -0
- package/src/main/pc-agent-scripts/take-screenshot.ps1 +24 -0
- package/src/main/pc-agent-scripts/win-action.ps1 +380 -0
- package/src/main/plugins/plugin-loader.js +306 -0
- package/src/main/skills/skill-manager.js +265 -0
- package/src/main/syntax-validator.js +455 -0
- package/src/main/task-daemon.js +117 -0
- package/src/main/telegram/telegram-service.js +835 -0
- package/src/main/tools/browser-tools.js +516 -0
- package/src/main/tools/file-tools.js +1126 -0
- package/src/main/tools/git-tools.js +79 -0
- package/src/main/tools/google-tools.js +566 -0
- package/src/main/tools/index.js +36 -0
- package/src/main/tools/media-tools.js +42 -0
- package/src/main/tools/system-tools.js +295 -0
- package/src/main/tools/task-tools.js +73 -0
- package/src/main/tools/telegram-tools.js +101 -0
- package/src/renderer/index.html +24 -0
- package/src/renderer/public/favicon.ico +0 -0
- package/src/renderer/public/icon-256.png +0 -0
- package/src/renderer/public/icon.svg +1 -0
- package/src/renderer/public/manifest.json +25 -0
- package/src/renderer/public/robot-simulator.html +1640 -0
- package/src/renderer/src/App.jsx +304 -0
- package/src/renderer/src/api/ai/awareness.js +294 -0
- package/src/renderer/src/api/ai/chatSummarizer.js +79 -0
- package/src/renderer/src/api/ai/contextCompactor.js +129 -0
- package/src/renderer/src/api/ai/contextManager.js +1130 -0
- package/src/renderer/src/api/ai/core.js +167 -0
- package/src/renderer/src/api/ai/index.js +4 -0
- package/src/renderer/src/api/ai/memoryGroomer.js +101 -0
- package/src/renderer/src/api/ai/persona.js +115 -0
- package/src/renderer/src/api/ai/planning.js +317 -0
- package/src/renderer/src/api/ai/relationship.js +177 -0
- package/src/renderer/src/api/ai/skillSynthesizer.js +168 -0
- package/src/renderer/src/api/ai/tools.js +167 -0
- package/src/renderer/src/api/ai/utils.js +359 -0
- package/src/renderer/src/api/db.js +1013 -0
- package/src/renderer/src/api/oramaStore.js +592 -0
- package/src/renderer/src/api/ragPipeline.js +87 -0
- package/src/renderer/src/api/subagent/subagentExecutor.js +780 -0
- package/src/renderer/src/api/subagent/subagentPrompt.js +44 -0
- package/src/renderer/src/api/subagent/subagentStore.js +173 -0
- package/src/renderer/src/api/taskExecutor.js +18 -0
- package/src/renderer/src/api/taskStore.js +315 -0
- package/src/renderer/src/api/tools/core-tools.js +707 -0
- package/src/renderer/src/api/tools/index.js +151 -0
- package/src/renderer/src/api/turnPairMigrator.js +200 -0
- package/src/renderer/src/api/vectorMemory.js +136 -0
- package/src/renderer/src/api/wakeWord.js +101 -0
- package/src/renderer/src/api/web-bridge.js +885 -0
- package/src/renderer/src/api/webSpeech.js +178 -0
- package/src/renderer/src/api/workspaceRag.js +76 -0
- package/src/renderer/src/assets/electron.svg +10 -0
- package/src/renderer/src/assets/icon.svg +1 -0
- package/src/renderer/src/assets/main.css +589 -0
- package/src/renderer/src/assets/music-cover.png +0 -0
- package/src/renderer/src/assets/wavy-lines.svg +25 -0
- package/src/renderer/src/components/Chat/ApprovalBubble.jsx +127 -0
- package/src/renderer/src/components/Chat/CodeBlock.jsx +83 -0
- package/src/renderer/src/components/Chat/DurableTaskBubble.jsx +455 -0
- package/src/renderer/src/components/Chat/FileDiffModal.jsx +328 -0
- package/src/renderer/src/components/Chat/GeminiWidgets.jsx +82 -0
- package/src/renderer/src/components/Chat/MemoryFooterBubble.jsx +34 -0
- package/src/renderer/src/components/Chat/MessageBubble.jsx +459 -0
- package/src/renderer/src/components/Chat/PluginExecutionBubble.jsx +41 -0
- package/src/renderer/src/components/Chat/ThinkingBubble.jsx +316 -0
- package/src/renderer/src/components/Chat/YoutubeSearchBubble.jsx +43 -0
- package/src/renderer/src/components/Chat/YoutubeSummaryBubble.jsx +40 -0
- package/src/renderer/src/components/Chat/index.js +11 -0
- package/src/renderer/src/components/ChatList.jsx +434 -0
- package/src/renderer/src/components/GlobalCameraManager.jsx +67 -0
- package/src/renderer/src/components/Versions.jsx +15 -0
- package/src/renderer/src/components/YoutubeMusicPlayer.jsx +375 -0
- package/src/renderer/src/components/camera/CameraPreview.jsx +236 -0
- package/src/renderer/src/components/config/AiEngineSection.jsx +363 -0
- package/src/renderer/src/components/config/CameraSection.jsx +100 -0
- package/src/renderer/src/components/config/PermissionsSection.jsx +130 -0
- package/src/renderer/src/components/config/ShortcutSection.jsx +102 -0
- package/src/renderer/src/components/config/VoiceSection.jsx +110 -0
- package/src/renderer/src/components/config/index.js +5 -0
- package/src/renderer/src/components/core/Avatar.jsx +2197 -0
- package/src/renderer/src/components/core/ConfirmModal.jsx +80 -0
- package/src/renderer/src/components/core/DraggableHoloCard.jsx +125 -0
- package/src/renderer/src/components/core/FloatingMenu.jsx +272 -0
- package/src/renderer/src/components/core/HoloCard.jsx +64 -0
- package/src/renderer/src/components/core/InputBar.jsx +1346 -0
- package/src/renderer/src/components/core/ProcessPanel.jsx +216 -0
- package/src/renderer/src/components/core/ResponseArea.jsx +149 -0
- package/src/renderer/src/components/core/StatusIndicator.jsx +59 -0
- package/src/renderer/src/components/core/ThoughtNeuralFlow.jsx +168 -0
- package/src/renderer/src/components/core/ToolClustersDeck.jsx +210 -0
- package/src/renderer/src/components/core/native-skills.js +43 -0
- package/src/renderer/src/components/neural-core/EmotionalCortexLobe.jsx +359 -0
- package/src/renderer/src/components/neural-core/NodeDissectionModal.jsx +57 -0
- package/src/renderer/src/components/neural-core/ProceduralMatrixLobe.jsx +193 -0
- package/src/renderer/src/components/neural-core/ProceduralSkillModal.jsx +53 -0
- package/src/renderer/src/components/neural-core/ResetAiModal.jsx +198 -0
- package/src/renderer/src/components/neural-core/SynapticMemoryLobe.jsx +204 -0
- package/src/renderer/src/components/neural-core/traitMeta.js +102 -0
- package/src/renderer/src/components/subagent/AgentChatFeed.jsx +603 -0
- package/src/renderer/src/components/subagent/AgentInspector.jsx +224 -0
- package/src/renderer/src/components/subagent/AgentSidebar.jsx +216 -0
- package/src/renderer/src/components/subagent/SubagentIntercom.jsx +572 -0
- package/src/renderer/src/components/subagent/SubagentTopologyMap.jsx +423 -0
- package/src/renderer/src/contexts/ApprovalContext.jsx +425 -0
- package/src/renderer/src/contexts/ChatContext.jsx +61 -0
- package/src/renderer/src/contexts/YoutubeMusicContext.jsx +333 -0
- package/src/renderer/src/data/faqData.js +202 -0
- package/src/renderer/src/hooks/agent/executeAgentTool.js +895 -0
- package/src/renderer/src/hooks/agent/index.js +4 -0
- package/src/renderer/src/hooks/agent/useMarkMusic.js +75 -0
- package/src/renderer/src/hooks/agent/useMarkPlan.js +2739 -0
- package/src/renderer/src/hooks/agent/useMarkState.js +173 -0
- package/src/renderer/src/hooks/agent/useMarkYoutube.js +82 -0
- package/src/renderer/src/hooks/agent/useRelationalGrowth.js +201 -0
- package/src/renderer/src/hooks/telegram/useTelegramBot.js +63 -0
- package/src/renderer/src/hooks/useAwareness.js +289 -0
- package/src/renderer/src/hooks/useChatArchiver.js +52 -0
- package/src/renderer/src/hooks/useConfirm.jsx +68 -0
- package/src/renderer/src/hooks/useMarkAgent.js +454 -0
- package/src/renderer/src/hooks/useMemoryGroomer.js +152 -0
- package/src/renderer/src/hooks/useVAD.js +511 -0
- package/src/renderer/src/hooks/useWebSpeechWakeWord.js +122 -0
- package/src/renderer/src/main.jsx +12 -0
- package/src/renderer/src/pages/ChatStudio.jsx +922 -0
- package/src/renderer/src/pages/Configuration.jsx +360 -0
- package/src/renderer/src/pages/GoogleWorkspace.jsx +293 -0
- package/src/renderer/src/pages/Guidebook.jsx +917 -0
- package/src/renderer/src/pages/Knowledge.jsx +241 -0
- package/src/renderer/src/pages/MarkHome.jsx +491 -0
- package/src/renderer/src/pages/NeuralCore.jsx +786 -0
- package/src/renderer/src/pages/Plugins.jsx +630 -0
- package/src/renderer/src/pages/SkillEditor.jsx +380 -0
- package/src/renderer/src/pages/Skills.jsx +219 -0
- package/src/renderer/src/pages/Subagents.jsx +342 -0
- package/src/renderer/src/pages/TelegramBot.jsx +343 -0
- package/src/renderer/src/utils/chatContentParser.js +203 -0
- package/src/renderer/src/utils/toolClusters.js +201 -0
- package/src/server/bin/sha3_wasm_bg.wasm +0 -0
- package/src/server/config-manager.js +57 -0
- package/src/server/index.js +195 -0
- package/src/server/launcher.js +87 -0
- package/src/server/memory/db-store.js +758 -0
- package/src/server/memory/orama-store.js +177 -0
- package/src/server/memory/vector-engine.js +109 -0
- package/src/server/routes/ai.routes.js +280 -0
- package/src/server/routes/awareness.routes.js +62 -0
- package/src/server/routes/chat.routes.js +61 -0
- package/src/server/routes/config.routes.js +41 -0
- package/src/server/routes/index.js +35 -0
- package/src/server/routes/integrations.routes.js +116 -0
- package/src/server/routes/memory.routes.js +256 -0
- package/src/server/routes/plugins.routes.js +72 -0
- package/src/server/routes/skills.routes.js +139 -0
- package/src/server/routes/subagents.routes.js +70 -0
- package/src/server/routes/tasks.routes.js +175 -0
- package/src/server/routes/workspace.routes.js +127 -0
- package/src/server/services/ai/ai-utils.js +161 -0
- package/src/server/services/ai/openai-provider.js +757 -0
- package/src/server/services/ai/web-provider.js +729 -0
- package/src/server/services/ai-bridge.js +46 -0
- package/src/server/services/deepseek-web.js +956 -0
- package/src/server/services/gemini-web.js +170 -0
- package/src/server/services/notification-service.js +91 -0
- package/src/server/services/updater.js +125 -0
- package/src/server/tools/awareness-tracker.js +292 -0
- package/src/server/tools/group-tools.js +1164 -0
- package/src/server/tools/media-tools.js +244 -0
- package/src/server/tools/pc-agent.js +327 -0
- package/src/server/tools/screen-service.js +51 -0
- package/src/server/ws-hub.js +168 -0
- 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
|