@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,363 @@
1
+ import { useState } from 'react'
2
+ import { FaCog } from 'react-icons/fa'
3
+ import { AlertTriangle } from 'lucide-react'
4
+
5
+ export const AiEngineSection = ({ config, setConfig }) => {
6
+ const [showCustomKey, setShowCustomKey] = useState(false)
7
+ const [showDeepseekToken, setShowDeepseekToken] = useState(false)
8
+
9
+ const handleAiProviderChange = (provider) =>
10
+ setConfig((prev) => ({ ...prev, aiProvider: provider }))
11
+
12
+ const handleModelChange = (e) => setConfig((prev) => ({ ...prev, model: e.target.value }))
13
+
14
+ const handleCustomEndpointChange = (e) =>
15
+ setConfig((prev) => ({ ...prev, customEndpoint: e.target.value }))
16
+
17
+ const handleCustomApiKeyChange = (e) =>
18
+ setConfig((prev) => ({ ...prev, customApiKey: e.target.value }))
19
+
20
+ const handleAwarenessEnabledChange = (e) =>
21
+ setConfig((prev) => ({ ...prev, awarenessEnabled: e.target.checked }))
22
+
23
+ const handlePersonalityChange = (e) =>
24
+ setConfig((prev) => ({ ...prev, personality: e.target.value }))
25
+
26
+ const handleTemperatureChange = (e) =>
27
+ setConfig((prev) => ({ ...prev, temperature: e.target.value }))
28
+
29
+ return (
30
+ <section className="space-y-5">
31
+ <h2 className="text-base font-bold uppercase tracking-wider opacity-70">AI Engine & Tools</h2>
32
+
33
+ {/* AI Provider Selector */}
34
+ <div id="tour-ai-provider" className="space-y-1.5">
35
+ <p className="text-sm font-semibold">AI Provider</p>
36
+ <select
37
+ className="select select-bordered w-full font-medium"
38
+ value={config.aiProvider || 'gemini-web'}
39
+ onChange={(e) => handleAiProviderChange(e.target.value)}
40
+ >
41
+ <option value="gemini-web">Gemini Web (Gratis)</option>
42
+ <option value="deepseek-web">DeepSeek Web (Gratis)</option>
43
+ <option value="custom">Custom API (OpenAI-Compatible)</option>
44
+ <option value="lm-studio">LM Studio (Local Offline)</option>
45
+ </select>
46
+ </div>
47
+
48
+ {config.aiProvider === 'deepseek-web' ? (
49
+ <div className="space-y-4">
50
+ {/* Risk Warning Notice */}
51
+ <div className="p-3 bg-warning/10 border border-warning/30 rounded-xl text-warning text-xs flex items-start gap-2.5 leading-relaxed">
52
+ <AlertTriangle className="w-4 h-4 shrink-0 mt-0.5 text-warning" />
53
+ <div>
54
+ <p className="font-semibold text-warning">Peringatan Risiko:</p>
55
+ <p className="text-white/80 mt-0.5">
56
+ Provider ini menggunakan sesi web/OAuth yang tidak dilisensikan secara resmi untuk
57
+ penggunaan proxy/router pihak ketiga. Akun dapat dibatasi atau diblokir (banned)
58
+ sementara oleh DeepSeek. Gunakan atas risiko sendiri.
59
+ </p>
60
+ </div>
61
+ </div>
62
+
63
+ <div className="space-y-1.5">
64
+ <div className="flex justify-between items-center">
65
+ <p className="text-sm font-semibold">DeepSeek User Token (Bearer)</p>
66
+ <button
67
+ type="button"
68
+ onClick={async () => {
69
+ try {
70
+ const text = await navigator.clipboard.readText()
71
+ if (text) setConfig((prev) => ({ ...prev, deepseekUserToken: text.trim() }))
72
+ } catch (_) {}
73
+ }}
74
+ className="text-xs text-primary hover:underline cursor-pointer"
75
+ >
76
+ Paste dari Clipboard
77
+ </button>
78
+ </div>
79
+ <div className="relative w-full">
80
+ <input
81
+ type={showDeepseekToken ? 'text' : 'password'}
82
+ placeholder="eyJhbGciOi..."
83
+ className="input input-bordered w-full font-mono text-xs pr-10"
84
+ value={config.deepseekUserToken || ''}
85
+ onChange={(e) =>
86
+ setConfig((prev) => ({ ...prev, deepseekUserToken: e.target.value }))
87
+ }
88
+ />
89
+ <button
90
+ type="button"
91
+ className="absolute right-3 top-1/2 -translate-y-1/2 opacity-50 hover:opacity-100 cursor-pointer"
92
+ onClick={() => setShowDeepseekToken(!showDeepseekToken)}
93
+ title={showDeepseekToken ? 'Sembunyikan Token' : 'Tampilkan Token'}
94
+ >
95
+ {showDeepseekToken ? (
96
+ <svg
97
+ xmlns="http://www.w3.org/2000/svg"
98
+ width="16"
99
+ height="16"
100
+ viewBox="0 0 24 24"
101
+ fill="none"
102
+ stroke="currentColor"
103
+ strokeWidth="2"
104
+ strokeLinecap="round"
105
+ strokeLinejoin="round"
106
+ >
107
+ <path d="M9.88 9.88a3 3 0 1 0 4.24 4.24" />
108
+ <path d="M10.73 5.08A10.43 10.43 0 0 1 12 5c7 0 10 7 10 7a13.16 13.16 0 0 1-1.67 2.68" />
109
+ <path d="M6.61 6.61A13.526 13.526 0 0 0 2 12s3 7 10 7a9.74 9.74 0 0 0 5.39-1.61" />
110
+ <line x1="2" x2="22" y1="2" y2="22" />
111
+ </svg>
112
+ ) : (
113
+ <svg
114
+ xmlns="http://www.w3.org/2000/svg"
115
+ width="16"
116
+ height="16"
117
+ viewBox="0 0 24 24"
118
+ fill="none"
119
+ stroke="currentColor"
120
+ strokeWidth="2"
121
+ strokeLinecap="round"
122
+ strokeLinejoin="round"
123
+ >
124
+ <path d="M2 12s3-7 10-7 10 7 10 7-3 7-10 7-10-7-10-7Z" />
125
+ <circle cx="12" cy="12" r="3" />
126
+ </svg>
127
+ )}
128
+ </button>
129
+ </div>
130
+
131
+ {/* Panduan Cara Mendapatkan Token */}
132
+ <div className="p-3 bg-base-200/60 rounded-xl border border-white/5 space-y-2 text-xs">
133
+ <div className="flex items-center gap-1.5 font-semibold text-primary">
134
+ <FaCog className="w-3.5 h-3.5" />
135
+ <span>Cara Mendapatkan User Token DeepSeek:</span>
136
+ </div>
137
+ <ol className="list-decimal list-inside space-y-1 text-white/70">
138
+ <li>
139
+ Buka dan login ke akunmu di{' '}
140
+ <a
141
+ href="https://chat.deepseek.com"
142
+ target="_blank"
143
+ rel="noreferrer"
144
+ className="text-primary underline"
145
+ >
146
+ chat.deepseek.com
147
+ </a>{' '}
148
+ di browser.
149
+ </li>
150
+ <li>
151
+ Tekan tombol keyboard <strong>F12</strong> (atau klik kanan &gt; Inspect) lalu
152
+ buka tab <strong>Console</strong>.
153
+ </li>
154
+ <li>Copy dan paste baris kode berikut ke dalam Console lalu tekan Enter:</li>
155
+ </ol>
156
+ <div className="flex items-center justify-between bg-black/50 p-2 rounded-lg border border-white/10 font-mono text-[11px] text-success">
157
+ <code className="truncate mr-2">
158
+ JSON.parse(localStorage.getItem('userToken')).value
159
+ </code>
160
+ <button
161
+ type="button"
162
+ onClick={() =>
163
+ navigator.clipboard.writeText(
164
+ "JSON.parse(localStorage.getItem('userToken')).value"
165
+ )
166
+ }
167
+ className="btn btn-xs btn-ghost text-white/50 hover:text-white shrink-0"
168
+ title="Salin snippet"
169
+ >
170
+ Salin Kode
171
+ </button>
172
+ </div>
173
+ <p className="text-[11px] text-white/40">
174
+ Salin nilai token yang muncul (tanpa tanda kutip), lalu tempelkan ke kolom input di
175
+ atas. Token ini otomatis memecahkan challenge anti-bot WASM DeepSeek secara lokal!
176
+ </p>
177
+ </div>
178
+ </div>
179
+ </div>
180
+ ) : config.aiProvider === 'gemini-web' || !config.aiProvider ? (
181
+ <div className="space-y-4">
182
+ <div className="space-y-1.5">
183
+ <p className="text-sm font-semibold">Model Gemini</p>
184
+ <select
185
+ className="select select-bordered w-full"
186
+ value={config.geminiWebModel || 'gemini-3.6-flash'}
187
+ onChange={(e) => setConfig((prev) => ({ ...prev, geminiWebModel: e.target.value }))}
188
+ >
189
+ <option value="gemini-3.6-flash">gemini-3.6-flash (Model Utama Terbaru)</option>
190
+ <option value="gemini-3.5-flash">gemini-3.5-flash (Stabil & Seimbang)</option>
191
+ <option value="gemini-3.5-flash-thinking">
192
+ gemini-3.5-flash-thinking (Penalaran Mendalam)
193
+ </option>
194
+ <option value="gemini-3.5-flash-thinking-lite">
195
+ gemini-3.5-flash-thinking-lite (Penalaran Cepat)
196
+ </option>
197
+ <option value="gemini-auto">gemini-auto (Otomatis Server)</option>
198
+ <option value="gemini-flash-lite">gemini-flash-lite (Super Cepat)</option>
199
+ </select>
200
+ <p className="text-xs opacity-50 mt-1">
201
+ Provider bawaan tanpa API Key. Membutuhkan koneksi internet (tidak mendukung input
202
+ gambar).
203
+ </p>
204
+ </div>
205
+ </div>
206
+ ) : config.aiProvider === 'custom' ? (
207
+ <div className="space-y-4">
208
+ <div className="space-y-1.5">
209
+ <p className="text-sm font-semibold">Custom Endpoint URL</p>
210
+ <input
211
+ type="text"
212
+ placeholder="Contoh: https://api.openai.com/v1/chat/completions"
213
+ className={`input input-bordered w-full ${config.customEndpoint && !config.customEndpoint.trim().endsWith('/chat/completions') ? 'input-error' : ''}`}
214
+ value={config.customEndpoint || ''}
215
+ onChange={handleCustomEndpointChange}
216
+ />
217
+ {config.customEndpoint &&
218
+ !config.customEndpoint.trim().endsWith('/chat/completions') ? (
219
+ <p className="text-xs text-error mt-1 font-medium">
220
+ URL endpoint tidak memenuhi standar format OpenAI-Compatible.
221
+ </p>
222
+ ) : (
223
+ <p className="text-xs opacity-50 mt-1">
224
+ Pastikan Endpoint mendukung standar format <strong>OpenAI-Compatible</strong>.
225
+ </p>
226
+ )}
227
+ </div>
228
+ <div className="space-y-1.5">
229
+ <p className="text-sm font-semibold">Custom Model ID</p>
230
+ <input
231
+ type="text"
232
+ placeholder="Contoh: gpt-4o-mini"
233
+ className="input input-bordered w-full"
234
+ value={config.customModel || ''}
235
+ onChange={(e) => setConfig((prev) => ({ ...prev, customModel: e.target.value }))}
236
+ />
237
+ </div>
238
+ <div className="space-y-1.5">
239
+ <p className="text-sm font-semibold">Custom API Key</p>
240
+ <div className="relative w-full">
241
+ <input
242
+ type={showCustomKey ? 'text' : 'password'}
243
+ placeholder="Masukkan API Key (jika diperlukan)"
244
+ className="input input-bordered w-full pr-10"
245
+ value={config.customApiKey || ''}
246
+ onChange={handleCustomApiKeyChange}
247
+ />
248
+ <button
249
+ type="button"
250
+ className="absolute right-3 top-1/2 -translate-y-1/2 opacity-50 hover:opacity-100 cursor-pointer"
251
+ onClick={() => setShowCustomKey(!showCustomKey)}
252
+ title={showCustomKey ? 'Sembunyikan API Key' : 'Tampilkan API Key'}
253
+ >
254
+ {showCustomKey ? (
255
+ <svg
256
+ xmlns="http://www.w3.org/2000/svg"
257
+ width="16"
258
+ height="16"
259
+ viewBox="0 0 24 24"
260
+ fill="none"
261
+ stroke="currentColor"
262
+ strokeWidth="2"
263
+ strokeLinecap="round"
264
+ strokeLinejoin="round"
265
+ >
266
+ <path d="M9.88 9.88a3 3 0 1 0 4.24 4.24" />
267
+ <path d="M10.73 5.08A10.43 10.43 0 0 1 12 5c7 0 10 7 10 7a13.16 13.16 0 0 1-1.67 2.68" />
268
+ <path d="M6.61 6.61A13.526 13.526 0 0 0 2 12s3 7 10 7a9.74 9.74 0 0 0 5.39-1.61" />
269
+ <line x1="2" x2="22" y1="2" y2="22" />
270
+ </svg>
271
+ ) : (
272
+ <svg
273
+ xmlns="http://www.w3.org/2000/svg"
274
+ width="16"
275
+ height="16"
276
+ viewBox="0 0 24 24"
277
+ fill="none"
278
+ stroke="currentColor"
279
+ strokeWidth="2"
280
+ strokeLinecap="round"
281
+ strokeLinejoin="round"
282
+ >
283
+ <path d="M2 12s3-7 10-7 10 7 10 7-3 7-10 7-10-7-10-7Z" />
284
+ <circle cx="12" cy="12" r="3" />
285
+ </svg>
286
+ )}
287
+ </button>
288
+ </div>
289
+ </div>
290
+ </div>
291
+ ) : (
292
+ <div className="space-y-1.5">
293
+ <p className="text-sm font-semibold">Model Selector (LM Studio)</p>
294
+ <input
295
+ type="text"
296
+ placeholder="Contoh: google/gemma-3-4b"
297
+ className="input input-bordered w-full"
298
+ value={config.model || ''}
299
+ onChange={handleModelChange}
300
+ />
301
+ <p className="text-xs opacity-40">
302
+ Nama model yang aktif di LM Studio. Pastikan sudah ter-load.
303
+ </p>
304
+ </div>
305
+ )}
306
+
307
+ {/* Awareness Engine Toggle */}
308
+ <div className="space-y-1.5 p-2 -mx-2 rounded-lg bg-base-200">
309
+ <div className="flex items-center justify-between">
310
+ <div>
311
+ <p className="text-sm font-semibold">Awareness Engine</p>
312
+ <p className="text-xs opacity-50 mt-1">
313
+ Mengizinkan Mark membaca log sistem/aktivitas dan memulai obrolan secara proaktif di
314
+ latar belakang.
315
+ </p>
316
+ </div>
317
+ <input
318
+ type="checkbox"
319
+ className="toggle toggle-primary"
320
+ checked={config.awarenessEnabled !== false}
321
+ onChange={handleAwarenessEnabledChange}
322
+ />
323
+ </div>
324
+ </div>
325
+
326
+ {/* System Persona */}
327
+ <div id="tour-persona" className="space-y-1.5 p-2 -mx-2 rounded-lg">
328
+ <p className="text-sm font-semibold">Gaya Bicara dan Kepribadian</p>
329
+ <textarea
330
+ className="textarea w-full h-72 leading-relaxed no-scrollbar resize-none"
331
+ placeholder="Deskripsikan kepribadian Mark..."
332
+ value={config.personality}
333
+ onChange={handlePersonalityChange}
334
+ />
335
+ </div>
336
+
337
+ {/* Temperature Slider */}
338
+ <div id="tour-temperature" className="space-y-2 p-2 -mx-2 rounded-lg">
339
+ <div className="flex items-center justify-between">
340
+ <p className="text-sm font-semibold">Temperature</p>
341
+ <span className="font-mono text-sm text-primary font-bold">{config.temperature}</span>
342
+ </div>
343
+ <input
344
+ type="range"
345
+ min="0"
346
+ max="1"
347
+ step="0.1"
348
+ value={config.temperature}
349
+ className="range range-primary range-xs w-full"
350
+ onChange={handleTemperatureChange}
351
+ />
352
+ <div className="flex justify-between px-2.5 mt-2 text-xs">
353
+ <span>0</span>
354
+ <span>0.2</span>
355
+ <span>0.4</span>
356
+ <span>0.6</span>
357
+ <span>0.8</span>
358
+ <span>1.0</span>
359
+ </div>
360
+ </div>
361
+ </section>
362
+ )
363
+ }
@@ -0,0 +1,100 @@
1
+ import { useEffect, useRef } from 'react'
2
+
3
+ export const ConfigCameraPreview = ({ deviceId, enabled }) => {
4
+ const videoRef = useRef(null)
5
+
6
+ useEffect(() => {
7
+ if (!enabled) return
8
+ let stream = null
9
+ let isMounted = true
10
+ const startCamera = async () => {
11
+ try {
12
+ const constraints = {
13
+ video: deviceId && deviceId !== 'default' ? { deviceId: { exact: deviceId } } : true
14
+ }
15
+ stream = await navigator.mediaDevices.getUserMedia(constraints)
16
+ if (videoRef.current && isMounted) {
17
+ videoRef.current.srcObject = stream
18
+ videoRef.current.play().catch((e) => console.error(e))
19
+ } else {
20
+ stream.getTracks().forEach((t) => t.stop())
21
+ }
22
+ } catch (err) {
23
+ console.error('Preview camera error:', err)
24
+ }
25
+ }
26
+ startCamera()
27
+ return () => {
28
+ isMounted = false
29
+ if (stream) stream.getTracks().forEach((t) => t.stop())
30
+ }
31
+ }, [deviceId, enabled])
32
+
33
+ if (!enabled) return null
34
+
35
+ return (
36
+ <div className="mt-4 rounded-xl overflow-hidden border border-white/10 bg-black/50 aspect-video relative flex items-center justify-center shadow-inner">
37
+ <video ref={videoRef} autoPlay playsInline muted className="w-full h-full object-cover" />
38
+ <div className="absolute top-2 left-2 flex items-center gap-2 px-2 py-1 bg-black/60 rounded text-xs font-mono text-white backdrop-blur-md">
39
+ <span className="w-2 h-2 rounded-full bg-red-500 animate-pulse"></span>
40
+ Live Preview
41
+ </div>
42
+ </div>
43
+ )
44
+ }
45
+
46
+ export const CameraSection = ({ config, setConfig, videoDevices }) => {
47
+ const handleCameraEnabledChange = (e) =>
48
+ setConfig((prev) => ({ ...prev, cameraEnabled: e.target.checked }))
49
+
50
+ const handleCameraDeviceIdChange = (e) =>
51
+ setConfig((prev) => ({ ...prev, cameraDeviceId: e.target.value }))
52
+
53
+ return (
54
+ <div className="space-y-6 p-2 -mx-2 rounded-lg">
55
+ <h2 className="text-base font-bold uppercase tracking-wider opacity-70 mb-5 flex items-center gap-2">
56
+ Kamera
57
+ </h2>
58
+
59
+ <div className="form-control">
60
+ <label className="label cursor-pointer p-0">
61
+ <span className="label-text text-sm font-semibold">Aktifkan Kamera AI</span>
62
+ <input
63
+ type="checkbox"
64
+ className="toggle toggle-primary"
65
+ checked={config.cameraEnabled !== false}
66
+ onChange={handleCameraEnabledChange}
67
+ />
68
+ </label>
69
+ <span className="text-xs opacity-50 mt-2 block">
70
+ Mengizinkan Mark menggunakan kamera (jika diminta) untuk melihat dunia fisik.
71
+ </span>
72
+ </div>
73
+
74
+ {config.cameraEnabled !== false && (
75
+ <div className="space-y-1.5">
76
+ <p className="text-sm font-semibold">Perangkat Kamera</p>
77
+ <select
78
+ className="select select-bordered w-full"
79
+ value={config.cameraDeviceId || 'default'}
80
+ onChange={handleCameraDeviceIdChange}
81
+ >
82
+ <option value="default">Default System Camera</option>
83
+ {videoDevices.map((cam) => (
84
+ <option key={cam.deviceId} value={cam.deviceId}>
85
+ {cam.label || `Camera ${cam.deviceId.substring(0, 5)}...`}
86
+ </option>
87
+ ))}
88
+ </select>
89
+ </div>
90
+ )}
91
+
92
+ {config.cameraEnabled !== false && (
93
+ <ConfigCameraPreview
94
+ deviceId={config.cameraDeviceId}
95
+ enabled={config.cameraEnabled !== false}
96
+ />
97
+ )}
98
+ </div>
99
+ )
100
+ }
@@ -0,0 +1,130 @@
1
+ import { useState, useEffect } from 'react'
2
+ import { ShieldCheck, Terminal, Folder, Trash2, ShieldAlert } from 'lucide-react'
3
+ import { getAlwaysAllowedPaths, removeAlwaysAllowedPath } from '../../api/db'
4
+
5
+ export const PermissionsSection = () => {
6
+ const [paths, setPaths] = useState([])
7
+ const [isDeleting, setIsDeleting] = useState(null)
8
+
9
+ const loadPaths = async () => {
10
+ try {
11
+ const list = await getAlwaysAllowedPaths()
12
+ setPaths(Array.isArray(list) ? list : [])
13
+ } catch (_) {
14
+ setPaths([])
15
+ }
16
+ }
17
+
18
+ useEffect(() => {
19
+ loadPaths()
20
+
21
+ const handleConfigUpdated = (e) => {
22
+ if (Array.isArray(e.detail?.alwaysAllowedPaths)) {
23
+ setPaths(e.detail.alwaysAllowedPaths)
24
+ }
25
+ }
26
+ window.addEventListener('config-updated', handleConfigUpdated)
27
+ return () => window.removeEventListener('config-updated', handleConfigUpdated)
28
+ }, [])
29
+
30
+ const handleDelete = async (target) => {
31
+ setIsDeleting(target)
32
+ try {
33
+ const updated = await removeAlwaysAllowedPath(target)
34
+ setPaths(Array.isArray(updated) ? updated : [])
35
+ } catch (e) {
36
+ console.error('Gagal menghapus izin whitelist:', e)
37
+ } finally {
38
+ setIsDeleting(null)
39
+ }
40
+ }
41
+
42
+ return (
43
+ <section className="space-y-4 p-2 -mx-2 rounded-lg">
44
+ <div>
45
+ <h2 className="text-base font-bold uppercase tracking-wider opacity-70 flex items-center gap-2">
46
+ <ShieldAlert className="w-4 h-4 text-warning" />
47
+ Keamanan & Izin Tool (Whitelist)
48
+ </h2>
49
+ <p className="text-xs text-white/50 mt-1">
50
+ Daftar folder dan perintah shell yang diizinkan selamanya tanpa memunculkan permintaan
51
+ konfirmasi.
52
+ </p>
53
+ </div>
54
+
55
+ <div className="space-y-2">
56
+ {paths.length === 0 ? (
57
+ <div className="flex flex-col items-center justify-center p-6 bg-base-200/50 rounded-xl border border-white/5 text-center space-y-2">
58
+ <ShieldCheck className="w-8 h-8 text-white/30" />
59
+ <p className="text-xs font-medium text-white/60">
60
+ Belum ada izin permanen yang tersimpan.
61
+ </p>
62
+ <p className="text-[11px] text-white/40 max-w-sm">
63
+ Ketika Mark meminta izin di percakapan, Anda dapat memilih "Izinkan Selamanya" untuk
64
+ mendaftarkannya ke sini.
65
+ </p>
66
+ </div>
67
+ ) : (
68
+ <div className="space-y-2 max-h-72 overflow-y-auto custom-scrollbar pr-1">
69
+ {paths.map((item) => {
70
+ const isCommand = String(item).startsWith('cmd:')
71
+ const displayVal = isCommand ? item.slice(4) : item
72
+
73
+ return (
74
+ <div
75
+ key={item}
76
+ className="flex items-center justify-between p-3 bg-base-200/80 rounded-xl border border-white/5 hover:border-white/10 transition-all gap-3 group"
77
+ >
78
+ <div className="flex items-center gap-2.5 min-w-0 flex-1">
79
+ <div className="p-1.5 rounded-lg bg-black/40 text-white/70 shrink-0">
80
+ {isCommand ? (
81
+ <Terminal className="w-3.5 h-3.5 text-warning" />
82
+ ) : (
83
+ <Folder className="w-3.5 h-3.5 text-primary" />
84
+ )}
85
+ </div>
86
+ <div className="flex flex-col min-w-0 flex-1">
87
+ <div className="flex items-center gap-2">
88
+ <span
89
+ className={`badge badge-xs font-mono text-[9px] px-1.5 py-0.5 ${
90
+ isCommand
91
+ ? 'bg-warning/15 text-warning border-warning/30'
92
+ : 'bg-primary/15 text-primary border-primary/30'
93
+ }`}
94
+ >
95
+ {isCommand ? 'Perintah Shell' : 'Folder / Berkas'}
96
+ </span>
97
+ </div>
98
+ <span
99
+ className="font-mono text-xs text-white/90 truncate mt-0.5"
100
+ title={displayVal}
101
+ >
102
+ {displayVal}
103
+ </span>
104
+ </div>
105
+ </div>
106
+
107
+ <button
108
+ type="button"
109
+ onClick={() => handleDelete(item)}
110
+ disabled={isDeleting === item}
111
+ className="btn btn-ghost btn-xs text-error hover:bg-error/20 p-1.5 h-auto rounded-lg transition-colors cursor-pointer shrink-0"
112
+ title="Cabut Izin Permanen"
113
+ >
114
+ {isDeleting === item ? (
115
+ <span className="loading loading-spinner loading-xs" />
116
+ ) : (
117
+ <Trash2 className="w-3.5 h-3.5" />
118
+ )}
119
+ </button>
120
+ </div>
121
+ )
122
+ })}
123
+ </div>
124
+ )}
125
+ </div>
126
+ </section>
127
+ )
128
+ }
129
+
130
+ export default PermissionsSection