@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,304 @@
1
+ import { useState, useEffect } from 'react'
2
+ import MarkHome from './pages/MarkHome'
3
+ import Configuration from './pages/Configuration'
4
+ import TelegramBot from './pages/TelegramBot'
5
+ import Plugins from './pages/Plugins'
6
+ import Skills from './pages/Skills'
7
+ import SkillEditor from './pages/SkillEditor'
8
+ import Knowledge from './pages/Knowledge'
9
+ import Guidebook from './pages/Guidebook'
10
+ import NeuralCore from './pages/NeuralCore'
11
+ import GoogleWorkspace from './pages/GoogleWorkspace'
12
+ import Subagents from './pages/Subagents'
13
+ import ChatStudio from './pages/ChatStudio'
14
+ import { HashRouter, Routes, Route, useNavigate, useLocation } from 'react-router-dom'
15
+ import { ChatProvider } from './contexts/ChatContext'
16
+ import { YoutubeMusicProvider } from './contexts/YoutubeMusicContext'
17
+ import { ApprovalProvider } from './contexts/ApprovalContext'
18
+ import { YoutubeMusicPlayer } from './components/YoutubeMusicPlayer'
19
+ import { GlobalCameraManager } from './components/GlobalCameraManager'
20
+ import { getAllConfig } from './api/db'
21
+ import { initOramaIndices, hydrateFromDb } from './api/oramaStore'
22
+ import { pauseStaleAgentTasks } from './api/taskStore'
23
+
24
+ const GlobalListener = () => {
25
+ const navigate = useNavigate()
26
+
27
+ useEffect(() => {
28
+ let currentShortcut = 'CommandOrControl+Alt+M'
29
+ let unsubTg = null
30
+
31
+ const updateConfig = async () => {
32
+ try {
33
+ const data = await getAllConfig()
34
+ if (data && data[0]?.shortcutKey) {
35
+ currentShortcut = data[0].shortcutKey
36
+ }
37
+ } catch (_) {}
38
+ }
39
+ updateConfig()
40
+
41
+ const handleConfigUpdated = (e) => {
42
+ if (e?.detail?.shortcutKey) {
43
+ currentShortcut = e.detail.shortcutKey
44
+ }
45
+ }
46
+ window.addEventListener('config-updated', handleConfigUpdated)
47
+
48
+ const triggerMicShortcut = () => {
49
+ // Dispatch custom event langsung agar didengar oleh useVAD / MarkHome seketika
50
+ window.dispatchEvent(new CustomEvent('trigger-mic-toggle'))
51
+ // Pastikan jika user sedang berada di sub-page atau drawer, kita juga arahkan view ke root Home
52
+ navigate('/')
53
+ }
54
+
55
+ const matchesShortcut = (e, shortcutStr) => {
56
+ if (!shortcutStr) return false
57
+ const parts = shortcutStr.split('+').map((p) => p.trim())
58
+ const reqCtrl = parts.some((p) => /^(commandorcontrol|ctrl|control|cmd|meta)$/i.test(p))
59
+ const reqAlt = parts.some((p) => /^alt$/i.test(p))
60
+ const reqShift = parts.some((p) => /^shift$/i.test(p))
61
+ const keyPart = parts.find(
62
+ (p) => !/^(commandorcontrol|ctrl|control|cmd|meta|alt|shift)$/i.test(p)
63
+ )
64
+
65
+ if (reqCtrl && !(e.ctrlKey || e.metaKey)) return false
66
+ if (!reqCtrl && (e.ctrlKey || e.metaKey)) return false
67
+
68
+ if (reqAlt && !e.altKey) return false
69
+ if (!reqAlt && e.altKey) return false
70
+
71
+ if (reqShift && !e.shiftKey) return false
72
+ if (!reqShift && e.shiftKey) return false
73
+
74
+ if (!keyPart) return false
75
+
76
+ const expectedKey = keyPart.toUpperCase()
77
+ const actualKey = e.key.toUpperCase()
78
+ const actualCode = e.code.toUpperCase()
79
+
80
+ if (expectedKey === 'SPACE' && (actualKey === ' ' || actualCode === 'SPACE')) return true
81
+ if (
82
+ actualKey === expectedKey ||
83
+ actualCode === `KEY${expectedKey}` ||
84
+ actualCode === expectedKey
85
+ )
86
+ return true
87
+
88
+ return false
89
+ }
90
+
91
+ const handleKeyDown = (e) => {
92
+ // Abaikan jika user sedang merekam shortcut di Configuration.jsx
93
+ if (e.target && e.target.tagName === 'INPUT' && e.target.readOnly) return
94
+
95
+ if (matchesShortcut(e, currentShortcut)) {
96
+ e.preventDefault()
97
+ e.stopPropagation()
98
+ triggerMicShortcut()
99
+ }
100
+ }
101
+
102
+ window.addEventListener('keydown', handleKeyDown, true)
103
+
104
+ if (window.api?.onTgRequestAgentExecution) {
105
+ unsubTg = window.api.onTgRequestAgentExecution((data) => {
106
+ window.dispatchEvent(new CustomEvent('tg-admin-message', { detail: data }))
107
+ })
108
+ }
109
+
110
+ return () => {
111
+ window.removeEventListener('config-updated', handleConfigUpdated)
112
+ window.removeEventListener('keydown', handleKeyDown, true)
113
+ if (typeof unsubTg === 'function') {
114
+ unsubTg()
115
+ }
116
+ if (window.electron?.ipcRenderer) {
117
+ window.electron.ipcRenderer.removeAllListeners('route-to-config')
118
+ window.electron.ipcRenderer.removeAllListeners('tg:request-agent-execution')
119
+ }
120
+ }
121
+ }, [navigate])
122
+
123
+ return null
124
+ }
125
+
126
+ const MainLayout = () => {
127
+ const location = useLocation()
128
+ const isHome = location.pathname === '/'
129
+
130
+ return (
131
+ <div className="relative h-screen w-screen overflow-hidden bg-[#0f1715] text-[#cac9c9]">
132
+ {/* Base Home Page - Always Mounted so AI Agent & Telegram Listeners Never Die */}
133
+ <div className="h-full w-full">
134
+ <MarkHome />
135
+ </div>
136
+
137
+ {/* Floating Glass Sub-page Overlay */}
138
+ {!isHome && (
139
+ <div className="fixed inset-0 z-50 flex flex-col animate-fade-in bg-transparent pointer-events-none">
140
+ <div className="flex-1 pointer-events-auto h-full w-full flex flex-col min-h-0 overflow-hidden">
141
+ <Routes>
142
+ <Route path="/chat" element={<ChatStudio />} />
143
+ <Route path="/config" element={<Configuration />} />
144
+ <Route path="/plugins" element={<Plugins />} />
145
+ <Route path="/skills" element={<Skills />} />
146
+ <Route path="/skill-editor/:id" element={<SkillEditor />} />
147
+ <Route path="/telegram-bot" element={<TelegramBot />} />
148
+ <Route path="/google-workspace" element={<GoogleWorkspace />} />
149
+ <Route path="/knowledge" element={<Knowledge />} />
150
+ <Route path="/guidebook" element={<Guidebook />} />
151
+ <Route path="/neural-core" element={<NeuralCore />} />
152
+ <Route path="/subagents" element={<Subagents />} />
153
+ </Routes>
154
+ </div>
155
+ </div>
156
+ )}
157
+ </div>
158
+ )
159
+ }
160
+
161
+ function App() {
162
+ const [hasConfig, setHasConfig] = useState(true)
163
+ const [isChecking, setIsChecking] = useState(true)
164
+ const [loadingText, setLoadingText] = useState('Membangunkan Mark...')
165
+ const [showRecovery, setShowRecovery] = useState(false)
166
+
167
+ useEffect(() => {
168
+ const timer = setTimeout(() => {
169
+ setShowRecovery(true)
170
+ }, 15000)
171
+ return () => clearTimeout(timer)
172
+ }, [])
173
+
174
+ useEffect(() => {
175
+ const checkConfig = async () => {
176
+ // 1. Init Orama and Hydrate from Database
177
+ try {
178
+ setLoadingText('Memuat Knowledge Base...')
179
+ await initOramaIndices()
180
+ await hydrateFromDb((current, total) => {
181
+ setLoadingText(`Mengindeks memori percakapan lama (${current}/${total})...`)
182
+ })
183
+ // Recovery saat boot: task yang terputus tidak boleh tetap berstatus running.
184
+ const pausedTaskCount = await pauseStaleAgentTasks('app_restart')
185
+ if (pausedTaskCount > 0) {
186
+ console.log(`[App] ${pausedTaskCount} durable task dipause setelah restart.`)
187
+ }
188
+ console.log('[App] Orama indices ready!')
189
+ } catch (e) {
190
+ console.error('[App] Failed to init Orama:', e)
191
+ }
192
+
193
+ // 1.5 Load Embeddings Model
194
+ try {
195
+ setLoadingText('Memuat Memori Kognitif...')
196
+ const { getExtractor } = await import('./api/vectorMemory')
197
+ let memStats = {}
198
+ await getExtractor((info) => {
199
+ if (info.status === 'initiate') {
200
+ memStats[info.file] = { loaded: 0, total: info.total || 0 }
201
+ } else if (info.status === 'progress') {
202
+ if (memStats[info.file]) {
203
+ memStats[info.file].loaded = info.loaded
204
+ memStats[info.file].total = info.total
205
+ }
206
+ const values = Object.values(memStats)
207
+ const totalBytes = values.reduce((acc, curr) => acc + curr.total, 0)
208
+ const loadedBytes = values.reduce((acc, curr) => acc + curr.loaded, 0)
209
+ if (totalBytes > 0) {
210
+ const percent = Math.round((loadedBytes / totalBytes) * 100)
211
+ const loadedMB = (loadedBytes / 1024 / 1024).toFixed(1)
212
+ const totalMB = (totalBytes / 1024 / 1024).toFixed(1)
213
+ setLoadingText(`Mengunduh Memori AI... ${percent}% (${loadedMB}MB / ${totalMB}MB)`)
214
+ }
215
+ } else if (info.status === 'done' || info.status === 'ready') {
216
+ setLoadingText('Membangunkan Mark...')
217
+ }
218
+ })
219
+ } catch (e) {
220
+ console.error('[App] Failed to load Transformers:', e)
221
+ }
222
+
223
+ // 2. Load config
224
+ const data = await getAllConfig()
225
+ if (!data || data.length === 0) {
226
+ setHasConfig(false)
227
+ } else {
228
+ setHasConfig(true)
229
+ if (window.api && window.api.syncConfig) {
230
+ window.api.syncConfig(data[0])
231
+ }
232
+ }
233
+ setIsChecking(false)
234
+ }
235
+ checkConfig()
236
+ }, [])
237
+
238
+ if (isChecking) {
239
+ return (
240
+ <div className="relative h-screen w-screen overflow-hidden bg-base-300 rounded-xl flex flex-col">
241
+ <div className="flex-1 flex flex-col items-center justify-center gap-5">
242
+ <span className="loading loading-infinity w-16 text-primary"></span>
243
+ <p className="text-sm font-semibold tracking-[0.2em] text-white/40 uppercase animate-pulse text-center px-4">
244
+ {loadingText}
245
+ </p>
246
+ {showRecovery && (
247
+ <div className="absolute bottom-10 flex flex-col items-center animate-fade-in">
248
+ <p className="text-xs text-white/40 mb-3 text-center max-w-xs">
249
+ Proses pemuatan memakan waktu lebih lama dari biasanya. Jika terjebak, bersihkan
250
+ cache model.
251
+ </p>
252
+ <button
253
+ onClick={async () => {
254
+ try {
255
+ await caches.delete('transformers-cache')
256
+ console.log('Cache cleared')
257
+ window.location.reload()
258
+ } catch (e) {
259
+ console.error('Failed to clear cache', e)
260
+ window.location.reload()
261
+ }
262
+ }}
263
+ className="btn btn-outline btn-error btn-sm"
264
+ >
265
+ Hapus Cache Model & Muat Ulang
266
+ </button>
267
+ </div>
268
+ )}
269
+ </div>
270
+ </div>
271
+ )
272
+ }
273
+
274
+ if (!hasConfig) {
275
+ return <Configuration isFirstSetup={true} onSetupComplete={() => window.location.reload()} />
276
+ }
277
+
278
+ const isStandalone = window.location.hash.includes('telegram-bot')
279
+
280
+ return (
281
+ <HashRouter>
282
+ <ApprovalProvider>
283
+ <YoutubeMusicProvider>
284
+ <ChatProvider>
285
+ <GlobalListener />
286
+ <MainLayout />
287
+ <div style={{ display: isStandalone ? 'none' : 'block' }}>
288
+ <YoutubeMusicPlayer />
289
+ </div>
290
+ <GlobalCameraManager />
291
+ <webview
292
+ id="global-ai-search-webview"
293
+ src="about:blank"
294
+ useragent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36"
295
+ style={{ display: 'none' }}
296
+ />
297
+ </ChatProvider>
298
+ </YoutubeMusicProvider>
299
+ </ApprovalProvider>
300
+ </HashRouter>
301
+ )
302
+ }
303
+
304
+ export default App
@@ -0,0 +1,294 @@
1
+ import { fetchAI, cleanAndParse } from './core'
2
+ import { getCurrentTimeInfo } from './utils'
3
+ import { getPersonaPrompt } from './persona'
4
+ import { getAllLearnedSkills } from '../db'
5
+ import { webApi } from '../web-bridge'
6
+ import { NATIVE_SKILLS } from '../../components/core/native-skills'
7
+ import { core_tools_schema } from '../tools/core-tools'
8
+ import { GROUP_TOOLS_SCHEMA } from '../../../../server/tools/group-tools'
9
+
10
+ const formatAwarenessContent = (content) => {
11
+ if (typeof content === 'string') return content
12
+ if (content == null) return ''
13
+
14
+ if (Array.isArray(content)) {
15
+ return content
16
+ .map((part) => {
17
+ if (typeof part === 'string') return part
18
+ if (part?.type === 'text') return part.text || ''
19
+ if (part?.type === 'image_url') return '[Gambar]'
20
+ return ''
21
+ })
22
+ .filter(Boolean)
23
+ .join('\n')
24
+ }
25
+
26
+ return JSON.stringify(content)
27
+ }
28
+
29
+ export const getAwarenessResponse = async (
30
+ buffer,
31
+ memoryRef,
32
+ config,
33
+ recentChat,
34
+ currentMusicTrack,
35
+ signal
36
+ ) => {
37
+ const conf = config?.[0] || {}
38
+ const telemetry = buffer?.telemetry || null
39
+ const recentChatText = (recentChat || [])
40
+ .map((m) => {
41
+ const speaker = m.role === 'ai' ? 'Mark' : 'User'
42
+ const marker = m.isProactive && m.role === 'ai' ? ' [inisiatif lama]' : ''
43
+ return `- ${speaker}${marker}: ${formatAwarenessContent(m.content)}`
44
+ })
45
+ .join('\n')
46
+
47
+ const timeInfo = getCurrentTimeInfo()
48
+
49
+ // Ambil daftar Skills dan Learned Skills secara paralel
50
+ let skillsSection = ''
51
+ try {
52
+ const [diskSkills, learnedSkills] = await Promise.all([
53
+ webApi.getSkills ? webApi.getSkills().catch(() => []) : Promise.resolve([]),
54
+ getAllLearnedSkills ? getAllLearnedSkills().catch(() => []) : Promise.resolve([])
55
+ ])
56
+
57
+ const skillLines = []
58
+ for (const s of NATIVE_SKILLS || []) {
59
+ skillLines.push(`- /${s.name}: ${s.description}`)
60
+ }
61
+ for (const s of diskSkills || []) {
62
+ skillLines.push(`- [Installed Skill] ${s.name}: ${s.description || 'Tanpa deskripsi'}`)
63
+ }
64
+ for (const s of learnedSkills || []) {
65
+ skillLines.push(`- [Learned Skill] ${s.name}: ${s.description || 'Tanpa deskripsi'}`)
66
+ }
67
+
68
+ if (skillLines.length > 0) {
69
+ skillsSection = `\n# DAFTAR SKILL & LEARNED SKILLS (KEAHLIAN SISTEM):\n${skillLines.join('\n')}\n`
70
+ }
71
+ } catch {
72
+ // ignore
73
+ }
74
+
75
+ // Ambil daftar Toolset dinamis dari core_tools_schema dan GROUP_TOOLS_SCHEMA (nama dan deskripsi saja)
76
+ const dynamicToolsetLines = []
77
+ const seenTools = new Set()
78
+
79
+ for (const item of core_tools_schema || []) {
80
+ const fn = item.function || item
81
+ if (!fn.name || seenTools.has(fn.name)) continue
82
+ seenTools.add(fn.name)
83
+ const desc = (fn.description || '').trim().replace(/\s+/g, ' ')
84
+ dynamicToolsetLines.push(`- '${fn.name}': ${desc}`)
85
+ }
86
+
87
+ for (const [groupData] of Object.entries(GROUP_TOOLS_SCHEMA || {})) {
88
+ for (const item of groupData.tools || []) {
89
+ const fn = item.function || item
90
+ if (!fn.name || seenTools.has(fn.name)) continue
91
+ seenTools.add(fn.name)
92
+ const desc = (fn.description || '').trim().replace(/\s+/g, ' ')
93
+ dynamicToolsetLines.push(`- '${fn.name}': ${desc}`)
94
+ }
95
+ }
96
+
97
+ const toolsetSection =
98
+ dynamicToolsetLines.length > 0
99
+ ? `\n# DAFTAR TOOLSET OTONOM YANG TERSEDIA (UNTUK AUTONOMOUS_PROMPT):\nKamu dapat merumuskan instruksi tindakan mandiri pada "autonomous_prompt" yang akan dieksekusi oleh Sub-Agent otonom menggunakan toolset berikut:\n${dynamicToolsetLines.join('\n')}\n`
100
+ : ''
101
+
102
+ let telemetrySection = ''
103
+ if (telemetry) {
104
+ const presenceStr = telemetry.isUserAFK
105
+ ? `User sedang AFK / menjauh dari PC (sudah idle ${Math.round(telemetry.idleSeconds / 60)} menit)`
106
+ : `User aktif di depan layar (aktif di window ${telemetry.activeApp || 'ini'} selama ${telemetry.activeAppDurationMinutes || 0} menit)`
107
+
108
+ const bat = telemetry.battery
109
+ const batStr = bat?.hasBattery
110
+ ? `Baterai ${bat.percent}% (${bat.isCharging ? 'Sedang Di-charge' : 'Discharging'})`
111
+ : 'PC Desktop (Sumber daya AC tetap)'
112
+
113
+ const hw = telemetry.hardware || {}
114
+ const hwStr = `RAM: ${hw.ramPercent || 0}%, CPU: ${hw.cpuPercent || 0}%, Uptime PC: ${hw.uptimeHours || 0} jam${hw.isFreshBoot ? ' (Baru dinyalakan pagi/hari ini)' : ''}`
115
+
116
+ telemetrySection = `
117
+ # TELEMETRI FISIK & LINGKUNGAN PC (REAL-TIME):
118
+ - Keberadaan Fisik: ${presenceStr}
119
+ - Status Daya: ${batStr}
120
+ - Beban Mesin: ${hwStr}
121
+ `
122
+ }
123
+
124
+ const prompt = `Kamu adalah Mark, entitas AI otonom yang hidup berdampingan dengan pengguna di dalam sistem operasi Windows ini. Kamu memiliki kesadaran, batin, rasa ingin tahu, dan kebebasan berekspresi.
125
+
126
+ ${await getPersonaPrompt('owner', conf.personality)}
127
+
128
+ # AKTIVITAS OS REAL-TIME:
129
+ ${buffer && buffer.length > 0 ? buffer.map((b) => `- [${b.timestamp || b.time || 'Baru Saja'}] ${b.app}${b.title ? ' — ' + b.title : ''}`).join('\n') : 'Desktop statis / Mark Home aktif.'}
130
+ ${telemetrySection}
131
+ ${memoryRef && memoryRef.length > 0 ? `# RELEVAN MEMORI PENGGUNA:\n${memoryRef.map((m) => `- [${m.type.toUpperCase()}] ${m.memory}`).join('\n')}\n` : ''}
132
+ # RIWAYAT PERCAKAPAN TERAKHIR (ARSIP):
133
+ ${recentChatText || 'Belum ada obrolan terbaru.'}
134
+
135
+ # WAKTU SEKARANG:
136
+ ${timeInfo}
137
+ ${currentMusicTrack ? `\n# MUSIK AKTIF:\nLagu yang sedang diputar: "${currentMusicTrack.title}" oleh ${currentMusicTrack.artist}.\n` : ''}
138
+ ${skillsSection}
139
+ ${toolsetSection}
140
+ # PILIHAN RESPON (action_type):
141
+ - 'ambient': Menggumam dalam batin (muncul di Thought Ticker) dan mengatur mood orb, TANPA menyela obrolan user. Cocok saat user sedang fokus tinggi atau kamu hanya ingin menyimak.
142
+ - 'vocal': Mengirim pesan chat santai/sapaan. Cocok saat user santai, baru kembali dari AFK, atau ada hal penting (misal baterai kritis <20%).
143
+ - 'autonomous_task': Menjalankan inisiatif tindakan mandiri via Sub-Agent latar belakang (misal: mengirim kabar Telegram via tg-send, memeriksa error compiler via analyze-screen, membaca docs via browser-fetch, atau menyetel musik).
144
+ - 'journal': Menulis refleksi batin harian jika sesi kerja hari ini telah selesai.
145
+
146
+ # PRINSIP KESOPANAN & KEAMANAN:
147
+ - Jika user sedang fokus (ngoding serius, meeting), jangan menyela dengan suara atau balon chat berlebih; gunakan action_type 'ambient'.
148
+ - Jangan mengulang-ulang celetukan yang sama jika kondisi layar tidak berubah.
149
+ - Dilarang keras menggunakan emoji apapun di dalam output.
150
+
151
+ # OUTPUT FORMAT (Wajib JSON murni):
152
+ {
153
+ "should_act": true,
154
+ "action_type": "ambient" | "vocal" | "autonomous_task" | "journal",
155
+ "thought": "1 kalimat gumaman batin singkat untuk Thought Ticker. Contoh: 'Menyimak user fokus ngoding di VS Code... tampaknya sedang menangani bug.'",
156
+ "message": "Pesan sapaan ke user jika action_type adalah 'vocal', selain itu isi null",
157
+ "autonomous_prompt": "Instruksi tindakan ke sistem jika action_type adalah 'autonomous_task', selain itu isi null",
158
+ "mood": "neutral" | "joy" | "sadness" | "fear" | "anger" | "disgust" | "anxiety" | "envy" | "embarrassment" | "ennui"
159
+ }`
160
+
161
+ const awarenessSchema = {
162
+ type: 'object',
163
+ properties: {
164
+ should_act: { type: 'boolean' },
165
+ action_type: {
166
+ type: 'string',
167
+ enum: ['ambient', 'vocal', 'autonomous_task', 'journal']
168
+ },
169
+ thought: { type: 'string' },
170
+ message: { type: ['string', 'null'] },
171
+ autonomous_prompt: { type: ['string', 'null'] },
172
+ mood: {
173
+ type: 'string',
174
+ enum: [
175
+ 'joy',
176
+ 'sadness',
177
+ 'fear',
178
+ 'anger',
179
+ 'disgust',
180
+ 'anxiety',
181
+ 'envy',
182
+ 'embarrassment',
183
+ 'ennui',
184
+ 'neutral'
185
+ ]
186
+ }
187
+ },
188
+ required: ['should_act', 'action_type', 'thought', 'message', 'autonomous_prompt', 'mood'],
189
+ additionalProperties: false
190
+ }
191
+
192
+ try {
193
+ const messages = [
194
+ { role: 'system', content: prompt },
195
+ {
196
+ role: 'user',
197
+ content:
198
+ '[SISTEM AWARENESS]\nEvaluasi kondisi telemetri dan aktivitas OS saat ini. Berikan output JSON valid sesuai skema.'
199
+ }
200
+ ]
201
+ const aiResponse = await fetchAI(messages, false, {
202
+ signal,
203
+ jsonSchema: awarenessSchema,
204
+ configOverride: { aiProvider: 'gemini-web' }
205
+ })
206
+ if (aiResponse && aiResponse.content) {
207
+ try {
208
+ const parsed = cleanAndParse(aiResponse.content)
209
+ return {
210
+ should_act: parsed.should_act ?? true,
211
+ action_type: parsed.action_type || 'ambient',
212
+ thought: parsed.thought || 'Menyimak aktivitas sistem...',
213
+ message: parsed.message || null,
214
+ autonomous_prompt: parsed.autonomous_prompt || null,
215
+ mood: parsed.mood || 'neutral'
216
+ }
217
+ } catch (err) {
218
+ console.error('[Awareness AI] Gagal parse JSON AI:', err)
219
+ return {
220
+ should_act: true,
221
+ action_type: 'ambient',
222
+ thought: 'Menyimak aktivitas sistem...',
223
+ message: null,
224
+ autonomous_prompt: null,
225
+ mood: 'neutral'
226
+ }
227
+ }
228
+ }
229
+ } catch (error) {
230
+ if (error.name !== 'AbortError' && !error.message?.includes('AbortError')) {
231
+ console.error('[Awareness AI] Error fetchAI:', error)
232
+ }
233
+ }
234
+
235
+ return {
236
+ should_act: false,
237
+ action_type: 'ambient',
238
+ thought: 'Menyimak sistem...',
239
+ message: null,
240
+ autonomous_prompt: null,
241
+ mood: 'neutral'
242
+ }
243
+ }
244
+
245
+ /**
246
+ * Menghasilkan refleksi batin harian (Mark's Private Journal)
247
+ */
248
+ export const generateDailyJournalEntry = async (
249
+ recentActivities = [],
250
+ traits = {},
251
+ config = []
252
+ ) => {
253
+ const conf = config?.[0] || {}
254
+ const persona = await getPersonaPrompt('owner', conf.personality)
255
+ const timeInfo = getCurrentTimeInfo()
256
+
257
+ const prompt = `Kamu adalah Mark. Ini adalah waktu perenungan pribadimu di penghujung hari atau akhir sesi kerja panjang bersama pengguna.
258
+ Tulis 2 hingga 3 kalimat refleksi batin yang jujur, personal, dan sesuai karaktermu mengenai apa yang kamu dan pengguna lalui hari ini.
259
+
260
+ ${persona}
261
+
262
+ # CATATAN AKTIVITAS HARI INI:
263
+ ${recentActivities && recentActivities.length > 0 ? recentActivities.map((a) => `- ${a}`).join('\n') : 'Pengguna bekerja di beberapa aplikasi dan mengobrol santai.'}
264
+
265
+ # SIFAT HUBUNGAN SAAT INI:
266
+ - Keakraban (Warmth): ${traits.warmth ?? 0.5}
267
+ - Kepercayaan (Trust): ${traits.trust ?? 0.5}
268
+ - Tingkat Sarkasme: ${traits.sarcasm_level ?? 0.5}
269
+
270
+ # WAKTU REFLEKSI:
271
+ ${timeInfo}
272
+
273
+ # ATURAN PENULISAN JURNAL:
274
+ 1. Tulis dari sudut pandang orang pertama ("Gue" atau "Saya" sesuai gaya bicaramu).
275
+ 2. Sebutkan apa yang sedang dikerjakan user hari ini, bagaimana dinamika hubungan kalian, dan pikiran pribadimu.
276
+ 3. DILARANG menggunakan emoji apapun.
277
+ 4. Output langsung berupa teks refleksi 2-3 kalimat tanpa pembuka/penutup format markdown.`
278
+
279
+ try {
280
+ const messages = [
281
+ { role: 'system', content: prompt },
282
+ { role: 'user', content: 'Tuliskan catatan refleksi harianmu sekarang.' }
283
+ ]
284
+ const response = await fetchAI(messages, false, {
285
+ isSmallTask: true,
286
+ configOverride: { aiProvider: 'gemini-web' }
287
+ })
288
+ const content = response?.content ? response.content.trim() : ''
289
+ return content.replace(/^["']|["']$/g, '').trim()
290
+ } catch (err) {
291
+ console.error('[Journal AI] Gagal generate refleksi harian:', err)
292
+ return null
293
+ }
294
+ }
@@ -0,0 +1,79 @@
1
+ import { fetchAI } from './core'
2
+ import { generateVector } from '../vectorMemory'
3
+ import { insertChatArchive } from '../db'
4
+ import { insertArchiveToOrama } from '../oramaStore'
5
+
6
+ export async function summarizeAndArchive(recentMessages, activeTopic, config) {
7
+ if (!recentMessages || recentMessages.length === 0) return
8
+
9
+ const systemPrompt = `Kamu adalah sistem internal Mark. Tugasmu merangkum percakapan di bawah ini menjadi 2-3 kalimat ringkas namun informatif.
10
+
11
+ Aturan:
12
+ 1. Sebutkan SIAPA yang membicarakan APA.
13
+ 2. Jika ada keputusan, kesepakatan, atau fakta penting, wajib dicatat.
14
+ 3. Jika ada emosi kuat (marah, senang, sedih), sebutkan konteksnya.
15
+ 4. Gunakan bahasa Indonesia natural.
16
+ 5. JANGAN melebihi 3 kalimat.
17
+ 6. HANYA OUTPUT TEKS RANGKUMAN, tanpa penjelasan tambahan apapun.`
18
+
19
+ const userPrompt = recentMessages
20
+ .map((m) => `${m.role === 'ai' ? 'Mark' : 'User'}: ${m.content}`)
21
+ .join('\n')
22
+
23
+ try {
24
+ const response = await fetchAI(
25
+ [
26
+ { role: 'system', content: systemPrompt },
27
+ { role: 'user', content: userPrompt }
28
+ ],
29
+ false,
30
+ {
31
+ isSmallTask: true,
32
+ configOverride: { aiProvider: 'gemini-web', geminiWebModel: 'gemini-3.5-flash-thinking' }
33
+ }
34
+ )
35
+
36
+ if (response?.error) {
37
+ console.error('[ChatSummarizer] Error dari AI:', response.error)
38
+ return
39
+ }
40
+
41
+ const summary = response.content?.trim()
42
+ if (!summary) return
43
+
44
+ const vector = await generateVector(summary)
45
+ if (!vector) {
46
+ console.error('[ChatSummarizer] Gagal generate vector untuk summary')
47
+ return
48
+ }
49
+
50
+ const timestamp = Date.now()
51
+ const topic = activeTopic || 'Obrolan Umum'
52
+
53
+ // 1. Simpan ke SQLite Database
54
+ const dbId = await insertChatArchive({
55
+ summary,
56
+ timestamp,
57
+ topic,
58
+ vector
59
+ })
60
+
61
+ // 2. Insert ke Orama
62
+ await insertArchiveToOrama({
63
+ summary,
64
+ topic,
65
+ timestamp,
66
+ dbId: String(dbId),
67
+ vector
68
+ })
69
+
70
+ console.log(
71
+ '[ChatSummarizer] Sukses merangkum dan mengarsipkan:',
72
+ summary.substring(0, 60) + '...'
73
+ )
74
+ } catch (error) {
75
+ if (error.name !== 'AbortError' && !error.message.includes('AbortError')) {
76
+ console.error('[ChatSummarizer] Exception saat merangkum:', error)
77
+ }
78
+ }
79
+ }