@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,193 @@
1
+ import React from 'react'
2
+ import {
3
+ FaGraduationCap,
4
+ FaSearch,
5
+ FaEye,
6
+ FaTrash,
7
+ FaBookOpen,
8
+ FaChevronRight
9
+ } from 'react-icons/fa'
10
+
11
+ export const ProceduralMatrixLobe = ({
12
+ learnedSkills = [],
13
+ skillSearch = '',
14
+ setSkillSearch,
15
+ onSelectSkill,
16
+ onDeleteSkill,
17
+ isFullView = false,
18
+ onNavigateToFull
19
+ }) => {
20
+ const filteredSkills = learnedSkills.filter(
21
+ (s) =>
22
+ s.name?.toLowerCase().includes(skillSearch.toLowerCase()) ||
23
+ (s.description && s.description.toLowerCase().includes(skillSearch.toLowerCase()))
24
+ )
25
+
26
+ if (isFullView) {
27
+ return (
28
+ <div className="flex-1 flex flex-col gap-4 min-h-0 overflow-hidden max-w-6xl mx-auto w-full pb-8">
29
+ {/* Header Vault Toolbar */}
30
+ <div className="p-4 bg-base-200/60 border border-white/5 rounded-2xl flex flex-wrap items-center justify-between gap-4 backdrop-blur-md shadow-lg">
31
+ <div>
32
+ <h2 className="text-sm font-bold font-mono text-base-content flex items-center gap-2 uppercase tracking-wider">
33
+ <FaGraduationCap className="text-primary" /> Learned Skill
34
+ </h2>
35
+ <p className="text-xs text-base-content/60 mt-0.5">
36
+ Skill yang dipelajari dan dirumuskan sendiri oleh Mark saat menyelesaikan tugas
37
+ sebelumnya.
38
+ </p>
39
+ </div>
40
+
41
+ {/* Search Bar */}
42
+ <div className="relative w-full sm:w-72">
43
+ <FaSearch className="absolute left-3 top-1/2 -translate-y-1/2 text-base-content/40 text-xs" />
44
+ <input
45
+ type="text"
46
+ value={skillSearch}
47
+ onChange={(e) => setSkillSearch(e.target.value)}
48
+ placeholder="Cari keahlian atau panduan..."
49
+ className="w-full bg-base-300/60 border border-white/10 rounded-xl pl-9 pr-3 py-2 text-xs text-base-content placeholder:text-base-content/30 outline-none focus:border-primary/50 font-mono"
50
+ />
51
+ </div>
52
+ </div>
53
+
54
+ {/* Skills Card Grid */}
55
+ <div className="flex-1 overflow-y-auto pr-1 custom-scrollbar">
56
+ {filteredSkills.length === 0 ? (
57
+ <div className="h-64 flex flex-col items-center justify-center text-center p-6 bg-base-200/40 border border-white/5 rounded-2xl">
58
+ <FaGraduationCap className="text-4xl text-base-content/20 mb-3" />
59
+ <h3 className="text-sm font-bold font-mono text-base-content/80">
60
+ Belum Ada Keahlian Baru
61
+ </h3>
62
+ <p className="text-xs text-base-content/50 max-w-md mt-1 leading-relaxed">
63
+ Mark akan secara otomatis mencatat keahlian baru ke daftar ini ketika berhasil
64
+ menyelesaikan tugas teknis yang berulang atau rumit.
65
+ </p>
66
+ </div>
67
+ ) : (
68
+ <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
69
+ {filteredSkills.map((skill) => (
70
+ <div
71
+ key={skill.id}
72
+ className="p-5 bg-base-200/50 hover:bg-base-200/80 border border-white/5 hover:border-primary/30 rounded-2xl backdrop-blur-md transition-all flex flex-col justify-between group shadow-md"
73
+ >
74
+ <div className="flex flex-col gap-3 pb-3">
75
+ <div className="flex items-center justify-between">
76
+ <span className="font-mono font-bold text-sm text-base-content flex items-center gap-1.5 uppercase">
77
+ {skill.name}
78
+ </span>
79
+ </div>
80
+ <p className="text-xs text-base-content/70 leading-relaxed line-clamp-3">
81
+ {skill.description || 'Tidak ada deskripsi singkat.'}
82
+ </p>
83
+ <span className="text-[10px] font-mono text-base-content/40">
84
+ {new Date(skill.updatedAt || Date.now()).toLocaleDateString('id-ID', {
85
+ dateStyle: 'medium'
86
+ })}
87
+ </span>
88
+ </div>
89
+
90
+ <div className="flex items-center justify-between pt-3 border-t border-white/5">
91
+ <button
92
+ type="button"
93
+ onClick={() => onSelectSkill(skill)}
94
+ className="px-3 py-1.5 bg-primary/10 hover:bg-primary/20 text-primary border border-primary/20 rounded-xl text-xs font-mono font-semibold transition-all flex items-center gap-1.5 cursor-pointer"
95
+ >
96
+ <FaEye size={12} /> Buka Panduan
97
+ </button>
98
+ <button
99
+ type="button"
100
+ onClick={() => onDeleteSkill(skill)}
101
+ className="p-2 text-base-content/40 hover:text-error hover:bg-error/10 rounded-xl transition-all cursor-pointer"
102
+ title="Hapus Skill"
103
+ >
104
+ <FaTrash size={12} />
105
+ </button>
106
+ </div>
107
+ </div>
108
+ ))}
109
+ </div>
110
+ )}
111
+ </div>
112
+ </div>
113
+ )
114
+ }
115
+
116
+ // Embedded Column
117
+ return (
118
+ <div className="lg:col-span-3 bg-base-200/50 backdrop-blur-md border border-white/5 rounded-2xl p-4 flex flex-col min-h-0 overflow-hidden shadow-xl">
119
+ <div className="flex items-center justify-between border-b border-white/5 pb-3 mb-3">
120
+ <div className="flex items-center gap-2 text-sm font-bold font-mono text-base-content">
121
+ <FaGraduationCap className="text-primary" /> Skill Yang Di Pelajari
122
+ </div>
123
+ {onNavigateToFull && (
124
+ <button
125
+ type="button"
126
+ onClick={onNavigateToFull}
127
+ className="text-[10px] font-mono text-base-content/50 hover:text-base-content flex items-center gap-1 cursor-pointer transition-colors"
128
+ >
129
+ Lihat Semua <FaChevronRight size={8} />
130
+ </button>
131
+ )}
132
+ </div>
133
+
134
+ {/* Search Mini */}
135
+ <div className="relative mb-3">
136
+ <FaSearch className="absolute left-3 top-1/2 -translate-y-1/2 text-base-content/30 text-xs" />
137
+ <input
138
+ type="text"
139
+ value={skillSearch}
140
+ onChange={(e) => setSkillSearch(e.target.value)}
141
+ placeholder="Cari keahlian..."
142
+ className="w-full bg-base-300/60 border border-white/10 rounded-xl pl-8 pr-3 py-1.5 text-xs text-base-content placeholder:text-base-content/30 outline-none focus:border-primary/50 font-mono"
143
+ />
144
+ </div>
145
+
146
+ {/* Skills List */}
147
+ <div className="flex-1 overflow-y-auto space-y-2 pr-1 custom-scrollbar">
148
+ {filteredSkills.length === 0 ? (
149
+ <div className="h-full flex flex-col items-center justify-center p-4 text-center text-base-content/40 text-xs">
150
+ <FaBookOpen className="text-2xl mb-2 text-base-content/20" />
151
+ <p>Belum ada keahlian yang dipelajari.</p>
152
+ </div>
153
+ ) : (
154
+ filteredSkills.map((skill) => (
155
+ <div
156
+ key={skill.id}
157
+ className="p-2.5 bg-base-300/40 hover:bg-base-300/70 border border-white/5 hover:border-primary/20 rounded-xl transition-all flex flex-col gap-1 group"
158
+ >
159
+ <div className="flex items-center justify-between">
160
+ <span className="font-mono font-bold uppercase text-xs text-base-content/90">
161
+ {skill.name}
162
+ </span>
163
+ <div className="flex items-center gap-1 opacity-0 group-hover:opacity-100 transition-opacity">
164
+ <button
165
+ type="button"
166
+ onClick={() => onSelectSkill(skill)}
167
+ className="p-1 text-base-content/60 hover:text-primary transition-colors"
168
+ title="Buka Detail Panduan"
169
+ >
170
+ <FaEye size={11} />
171
+ </button>
172
+ <button
173
+ type="button"
174
+ onClick={() => onDeleteSkill(skill)}
175
+ className="p-1 text-base-content/40 hover:text-error transition-colors"
176
+ title="Hapus"
177
+ >
178
+ <FaTrash size={10} />
179
+ </button>
180
+ </div>
181
+ </div>
182
+ <p className="text-[11px] text-base-content/60 line-clamp-2 leading-tight">
183
+ {skill.description}
184
+ </p>
185
+ </div>
186
+ ))
187
+ )}
188
+ </div>
189
+ </div>
190
+ )
191
+ }
192
+
193
+ export default ProceduralMatrixLobe
@@ -0,0 +1,53 @@
1
+ import React from 'react'
2
+ import ReactMarkdown from 'react-markdown'
3
+ import remarkGfm from 'remark-gfm'
4
+ import { FaGraduationCap, FaTimes } from 'react-icons/fa'
5
+ import rehypeExternalLinks from 'rehype-external-links'
6
+ import { CodeBlock } from '../Chat/CodeBlock'
7
+
8
+ export const ProceduralSkillModal = ({ skill, onClose }) => {
9
+ if (!skill) return null
10
+
11
+ return (
12
+ <div className="fixed inset-0 z-50 bg-black/80 backdrop-blur-xl flex items-center justify-center p-4 animate-fade-in">
13
+ <div className="w-full max-w-3xl max-h-[85vh] bg-base-200 border border-white/10 rounded-2xl flex flex-col shadow-2xl overflow-hidden">
14
+ {/* Header */}
15
+ <div className="px-6 py-4 border-b border-white/10 flex items-center justify-between bg-base-300/60">
16
+ <div className="flex items-center gap-3">
17
+ <div className="w-8 h-8 rounded-xl bg-primary/10 border border-primary/20 flex items-center justify-center text-primary">
18
+ <FaGraduationCap size={15} />
19
+ </div>
20
+ <div>
21
+ <h3 className="font-mono font-bold text-sm text-base-content uppercase">
22
+ {skill.name}
23
+ </h3>
24
+ </div>
25
+ </div>
26
+ <button
27
+ type="button"
28
+ onClick={onClose}
29
+ className="w-8 h-8 rounded-xl bg-base-300 hover:bg-base-100 flex items-center justify-center text-base-content/50 hover:text-base-content transition-all cursor-pointer"
30
+ >
31
+ <FaTimes size={13} />
32
+ </button>
33
+ </div>
34
+
35
+ <div className="flex-1 overflow-y-auto p-6 font-sans text-sm text-base-content/90 custom-scrollbar leading-relaxed custom-markdown">
36
+ <ReactMarkdown
37
+ remarkPlugins={[remarkGfm]}
38
+ rehypePlugins={[
39
+ [rehypeExternalLinks, { target: '_blank', rel: ['noopener', 'noreferrer'] }]
40
+ ]}
41
+ components={{
42
+ code: CodeBlock
43
+ }}
44
+ >
45
+ {skill.content || '*Tidak ada konten instruksi Markdown.*'}
46
+ </ReactMarkdown>
47
+ </div>
48
+ </div>
49
+ </div>
50
+ )
51
+ }
52
+
53
+ export default ProceduralSkillModal
@@ -0,0 +1,198 @@
1
+ import { useState, useEffect } from 'react'
2
+ import { createPortal } from 'react-dom'
3
+ import { FaTrash, FaCheckCircle, FaShieldAlt } from 'react-icons/fa'
4
+
5
+ export const ResetAiModal = ({ isOpen, onClose, onConfirm, isResetting = false }) => {
6
+ const [step, setStep] = useState(1)
7
+ const [inputText, setInputText] = useState('')
8
+ const [isSuccess, setIsSuccess] = useState(false)
9
+ const CONFIRM_PHRASE = 'RESET MARK'
10
+
11
+ useEffect(() => {
12
+ const handleKeyDown = (e) => {
13
+ if (e.key === 'Escape' && isOpen && !isResetting) {
14
+ handleClose()
15
+ }
16
+ }
17
+ if (isOpen) {
18
+ window.addEventListener('keydown', handleKeyDown)
19
+ }
20
+ return () => window.removeEventListener('keydown', handleKeyDown)
21
+ }, [isOpen, isResetting])
22
+
23
+ if (!isOpen) return null
24
+
25
+ const handleClose = () => {
26
+ if (isResetting) return
27
+ setStep(1)
28
+ setInputText('')
29
+ setIsSuccess(false)
30
+ onClose?.()
31
+ }
32
+
33
+ const handleNextStep = () => {
34
+ setStep(2)
35
+ }
36
+
37
+ const handleExecuteReset = async () => {
38
+ if (inputText.trim() !== CONFIRM_PHRASE) return
39
+ const success = await onConfirm()
40
+ if (success !== false) {
41
+ setIsSuccess(true)
42
+ setTimeout(() => {
43
+ handleClose()
44
+ }, 1600)
45
+ }
46
+ }
47
+
48
+ const modalContent = (
49
+ <div className="modal modal-open z-[99999] fixed inset-0 flex items-center justify-center bg-black/70 backdrop-blur-md animate-[response-fade-in_0.15s_ease-out_forwards]">
50
+ <div className="modal-box relative bg-base-300 border border-white/10 shadow-2xl z-10 max-w-md">
51
+ {/* Success State */}
52
+ {isSuccess ? (
53
+ <div className="py-6 flex flex-col items-center justify-center text-center gap-3">
54
+ <div className="w-14 h-14 rounded-full bg-success/20 text-success flex items-center justify-center border border-success/30 shadow-lg">
55
+ <FaCheckCircle className="text-2xl" />
56
+ </div>
57
+ <div>
58
+ <h3 className="font-bold text-lg text-success">Reset AI Berhasil</h3>
59
+ <p className="py-2 text-sm opacity-80">
60
+ Seluruh memori, riwayat chat, dan sifat Mark telah dikembalikan ke kondisi awal.
61
+ </p>
62
+ </div>
63
+ </div>
64
+ ) : (
65
+ <>
66
+ {/* Header Title */}
67
+ <h3 className="font-bold text-lg text-error">Reset Total AI (Tahap {step}/2)</h3>
68
+
69
+ {/* Step 1: Warning Details */}
70
+ {step === 1 && (
71
+ <div className="py-3 space-y-3">
72
+ <p className="text-sm opacity-90">
73
+ Apakah Anda yakin ingin mereset seluruh data memori dan riwayat Mark?
74
+ </p>
75
+ <div className="p-3 bg-base-200/80 rounded-xl border border-white/5 space-y-1.5 text-xs">
76
+ <div className="text-error font-semibold flex items-center gap-1.5">
77
+ <FaTrash size={10} /> Data yang akan dihapus:
78
+ </div>
79
+ <ul className="list-disc list-inside opacity-70 space-y-0.5 pl-1">
80
+ <li>Seluruh riwayat obrolan & sesi percakapan</li>
81
+ <li>Seluruh memori eksplisit (Vector RAG)</li>
82
+ <li>Seluruh potongan dokumen tersimpan</li>
83
+ <li>Seluruh skill yang dipelajari (Learned Skills)</li>
84
+ <li>Status sifat & karakter (kembali ke default netral)</li>
85
+ <li>Riwayat tugas mandiri & sub-agen</li>
86
+ </ul>
87
+ <div className="pt-2 text-primary font-semibold flex items-center gap-1.5 border-t border-white/5">
88
+ <FaShieldAlt size={10} /> Data yang dipertahankan:
89
+ </div>
90
+ <p className="opacity-70 pl-1">
91
+ Pengaturan API Key, model provider, prompt, dan konfigurasi umum sistem tetap
92
+ aman.
93
+ </p>
94
+ </div>
95
+
96
+ <div className="modal-action mt-4">
97
+ <button
98
+ type="button"
99
+ className="btn btn-ghost btn-sm"
100
+ onClick={(e) => {
101
+ e.preventDefault()
102
+ e.stopPropagation()
103
+ handleClose()
104
+ }}
105
+ >
106
+ Batal
107
+ </button>
108
+ <button
109
+ type="button"
110
+ className="btn btn-error btn-sm shadow-md"
111
+ onClick={(e) => {
112
+ e.preventDefault()
113
+ e.stopPropagation()
114
+ handleNextStep()
115
+ }}
116
+ >
117
+ Lanjutkan ke Konfirmasi Terakhir
118
+ </button>
119
+ </div>
120
+ </div>
121
+ )}
122
+
123
+ {/* Step 2: Final Verification via Typing */}
124
+ {step === 2 && (
125
+ <div className="py-3 space-y-3">
126
+ <p className="text-sm opacity-90">
127
+ Tindakan ini <strong className="text-error">tidak dapat dibatalkan</strong>. Untuk
128
+ mengonfirmasi penghapusan seluruh memori Mark, ketik teks di bawah:
129
+ </p>
130
+
131
+ <div className="p-3 bg-base-200 rounded-xl border border-error/20 text-center font-mono font-bold text-sm tracking-widest text-error select-all">
132
+ {CONFIRM_PHRASE}
133
+ </div>
134
+
135
+ <div>
136
+ <label className="block text-xs opacity-60 mb-1">
137
+ Ketik ulang kata konfirmasi:
138
+ </label>
139
+ <input
140
+ type="text"
141
+ autoFocus
142
+ value={inputText}
143
+ onChange={(e) => setInputText(e.target.value)}
144
+ placeholder="Ketik RESET MARK di sini"
145
+ className="w-full bg-base-200 border border-white/10 focus:border-error rounded-xl px-3 py-2 text-xs font-mono text-base-content outline-none transition-colors uppercase"
146
+ />
147
+ </div>
148
+
149
+ <div className="modal-action mt-4">
150
+ <button
151
+ type="button"
152
+ disabled={isResetting}
153
+ className="btn btn-ghost btn-sm"
154
+ onClick={(e) => {
155
+ e.preventDefault()
156
+ e.stopPropagation()
157
+ setStep(1)
158
+ }}
159
+ >
160
+ Kembali
161
+ </button>
162
+ <button
163
+ type="button"
164
+ disabled={inputText.trim() !== CONFIRM_PHRASE || isResetting}
165
+ className="btn btn-error btn-sm shadow-md gap-1.5"
166
+ onClick={(e) => {
167
+ e.preventDefault()
168
+ e.stopPropagation()
169
+ handleExecuteReset()
170
+ }}
171
+ >
172
+ {isResetting && <span className="loading loading-spinner loading-xs" />}
173
+ <span>{isResetting ? 'Mereset...' : 'Hapus & Reset AI'}</span>
174
+ </button>
175
+ </div>
176
+ </div>
177
+ )}
178
+ </>
179
+ )}
180
+ </div>
181
+ <div
182
+ className="modal-backdrop fixed inset-0 cursor-pointer bg-transparent"
183
+ onClick={(e) => {
184
+ e.preventDefault()
185
+ e.stopPropagation()
186
+ handleClose()
187
+ }}
188
+ />
189
+ </div>
190
+ )
191
+
192
+ if (typeof document !== 'undefined') {
193
+ return createPortal(modalContent, document.body)
194
+ }
195
+ return modalContent
196
+ }
197
+
198
+ export default ResetAiModal
@@ -0,0 +1,204 @@
1
+ import React, { useEffect } from 'react'
2
+ import ForceGraph2D from 'react-force-graph-2d'
3
+ import { FaNetworkWired, FaChevronRight } from 'react-icons/fa'
4
+ import { FiCheckCircle, FiRefreshCw } from 'react-icons/fi'
5
+
6
+ export const SynapticMemoryLobe = ({
7
+ graphData,
8
+ graphDimensions,
9
+ graphContainerRef,
10
+ fgRef,
11
+ groomResult,
12
+ isGrooming,
13
+ triggerGrooming,
14
+ loadBrainData,
15
+ onSelectNode,
16
+ isFullView = false,
17
+ onNavigateToFull
18
+ }) => {
19
+ useEffect(() => {
20
+ if (fgRef.current) {
21
+ fgRef.current.d3Force('charge').strength(-150)
22
+ fgRef.current.d3Force('link').distance(40)
23
+ }
24
+ }, [graphData, fgRef])
25
+
26
+ if (isFullView) {
27
+ return (
28
+ <div
29
+ ref={graphContainerRef}
30
+ className="flex-1 w-full h-full bg-base-200/50 backdrop-blur-md border border-white/5 rounded-2xl relative overflow-hidden shadow-2xl flex flex-col"
31
+ >
32
+ {/* Memory Grooming Control Toolbar */}
33
+ <div className="absolute top-4 left-4 z-20 flex flex-wrap items-center gap-3 p-2.5 bg-base-300/90 backdrop-blur-md border border-white/10 rounded-xl text-xs shadow-lg">
34
+ <div className="flex items-center gap-2 px-2 text-base-content/70 font-mono text-[11px]">
35
+ <FiCheckCircle className="text-primary" />
36
+ <span>
37
+ Pembersih Memori:{' '}
38
+ {groomResult.lastChecked
39
+ ? `Terakhir dirapikan ${new Date(groomResult.lastChecked).toLocaleTimeString([], {
40
+ hour: '2-digit',
41
+ minute: '2-digit'
42
+ })}`
43
+ : 'Siap merapikan data'}
44
+ </span>
45
+ </div>
46
+ {(groomResult.mergedCount > 0 || groomResult.deletedCount > 0) && (
47
+ <div className="flex items-center gap-2 pl-2 border-l border-white/10 font-mono text-[10px] text-base-content/70">
48
+ <span>{groomResult.mergedCount} digabung</span>
49
+ <span>{groomResult.deletedCount} dibersihkan</span>
50
+ </div>
51
+ )}
52
+ <button
53
+ type="button"
54
+ onClick={async () => {
55
+ await triggerGrooming(true)
56
+ await loadBrainData()
57
+ }}
58
+ disabled={isGrooming}
59
+ className="btn btn-xs btn-primary rounded-lg font-mono flex items-center gap-1.5"
60
+ >
61
+ <FiRefreshCw className={isGrooming ? 'animate-spin' : ''} />
62
+ <span>{isGrooming ? 'Sedang Merapikan...' : 'Rapikan & Bersihkan Duplikat'}</span>
63
+ </button>
64
+ </div>
65
+
66
+ <div className="flex-1 w-full h-full cursor-crosshair">
67
+ <ForceGraph2D
68
+ ref={fgRef}
69
+ width={graphDimensions.width}
70
+ height={graphDimensions.height}
71
+ graphData={graphData}
72
+ nodeLabel="name"
73
+ nodeColor={(node) => node.color}
74
+ nodeRelSize={4}
75
+ linkColor={() => 'rgba(255,255,255,0.15)'}
76
+ linkWidth={(link) => (link.source.id === 'core' || link.source === 'core' ? 2 : 1)}
77
+ linkCurvature={0.25}
78
+ linkDirectionalParticles={2}
79
+ linkDirectionalParticleWidth={1.5}
80
+ linkDirectionalParticleSpeed={0.005}
81
+ cooldownTicks={60}
82
+ onEngineStop={() => fgRef.current?.zoomToFit(400, 50)}
83
+ d3VelocityDecay={0.3}
84
+ onNodeClick={(node) => {
85
+ if (node.group === 3) {
86
+ onSelectNode(node)
87
+ fgRef.current?.centerAt(node.x, node.y, 1000)
88
+ fgRef.current?.zoom(3, 1000)
89
+ } else {
90
+ fgRef.current?.centerAt(node.x, node.y, 1000)
91
+ fgRef.current?.zoom(2.5, 1000)
92
+ }
93
+ }}
94
+ nodeCanvasObjectMode={() => 'after'}
95
+ nodeCanvasObject={(node, ctx, globalScale) => {
96
+ if (node.group === 0 || node.group === 1 || node.group === 2) {
97
+ const fontSize =
98
+ node.group === 0 ? 15 / globalScale : node.group === 1 ? 13 / globalScale : 10 / globalScale
99
+ if (globalScale > 0.5) {
100
+ ctx.font = `${fontSize}px Sans-Serif`
101
+ ctx.textAlign = 'center'
102
+ ctx.textBaseline = 'middle'
103
+ ctx.fillStyle = 'rgba(255,255,255,0.85)'
104
+ ctx.fillText(node.name, node.x, node.y + node.val + 8 / globalScale)
105
+ }
106
+ }
107
+ }}
108
+ />
109
+ </div>
110
+ </div>
111
+ )
112
+ }
113
+
114
+ // Embedded Column
115
+ return (
116
+ <div
117
+ ref={graphContainerRef}
118
+ className="lg:col-span-5 bg-base-200/50 backdrop-blur-md border border-white/5 rounded-2xl relative flex flex-col min-h-[380px] lg:min-h-0 overflow-hidden shadow-xl"
119
+ >
120
+ <div className="absolute top-3 left-4 z-20 flex items-center justify-between right-4 pointer-events-none">
121
+ <div className="flex items-center gap-2 text-xs font-bold font-mono text-base-content bg-base-300/80 backdrop-blur-md px-3 py-1.5 rounded-xl border border-white/10 shadow-md">
122
+ <FaNetworkWired className="text-primary" /> PETA JARINGAN MEMORI
123
+ </div>
124
+ {onNavigateToFull && (
125
+ <button
126
+ type="button"
127
+ onClick={onNavigateToFull}
128
+ className="pointer-events-auto text-[10px] font-mono text-base-content/60 hover:text-base-content bg-base-300/80 px-2.5 py-1.5 rounded-xl border border-white/10 flex items-center gap-1 shadow-md cursor-pointer transition-colors"
129
+ >
130
+ Layar Penuh <FaChevronRight size={8} />
131
+ </button>
132
+ )}
133
+ </div>
134
+
135
+ {/* Mini Trigger Bar */}
136
+ <div className="absolute bottom-3 left-3 right-3 z-20 flex items-center justify-between p-2.5 rounded-xl bg-base-300/90 backdrop-blur-md border border-white/10 text-xs text-base-content/80 shadow-md">
137
+ <div className="flex items-center gap-1.5 text-[11px] font-mono text-primary">
138
+ <FiCheckCircle className="text-primary" />
139
+ <span>{groomResult.lastChecked ? 'Memori Rapi' : 'Siap Dirapikan'}</span>
140
+ </div>
141
+ <button
142
+ type="button"
143
+ onClick={async () => {
144
+ await triggerGrooming(true)
145
+ await loadBrainData()
146
+ }}
147
+ disabled={isGrooming}
148
+ className="btn btn-xs btn-primary font-mono text-[10px] flex items-center gap-1"
149
+ >
150
+ <FiRefreshCw className={isGrooming ? 'animate-spin' : ''} />
151
+ <span>{isGrooming ? 'Merapikan...' : 'Rapikan Memori'}</span>
152
+ </button>
153
+ </div>
154
+
155
+ {/* 2D Canvas ForceGraph */}
156
+ <div className="flex-1 w-full h-full cursor-crosshair">
157
+ <ForceGraph2D
158
+ ref={fgRef}
159
+ width={graphDimensions.width}
160
+ height={graphDimensions.height}
161
+ graphData={graphData}
162
+ nodeLabel="name"
163
+ nodeColor={(node) => node.color}
164
+ nodeRelSize={4}
165
+ linkColor={() => 'rgba(255,255,255,0.08)'}
166
+ linkWidth={(link) => (link.source.id === 'core' || link.source === 'core' ? 1.5 : 1)}
167
+ linkCurvature={0.2}
168
+ linkDirectionalParticles={1}
169
+ linkDirectionalParticleWidth={1.2}
170
+ linkDirectionalParticleSpeed={0.004}
171
+ cooldownTicks={60}
172
+ onEngineStop={() => fgRef.current?.zoomToFit(400, 50)}
173
+ d3VelocityDecay={0.3}
174
+ onNodeClick={(node) => {
175
+ if (node.group === 3) {
176
+ onSelectNode(node)
177
+ fgRef.current?.centerAt(node.x, node.y, 1000)
178
+ fgRef.current?.zoom(3, 1000)
179
+ } else {
180
+ fgRef.current?.centerAt(node.x, node.y, 1000)
181
+ fgRef.current?.zoom(2.5, 1000)
182
+ }
183
+ }}
184
+ nodeCanvasObjectMode={() => 'after'}
185
+ nodeCanvasObject={(node, ctx, globalScale) => {
186
+ if (node.group === 0 || node.group === 1 || node.group === 2) {
187
+ const fontSize =
188
+ node.group === 0 ? 15 / globalScale : node.group === 1 ? 13 / globalScale : 10 / globalScale
189
+ if (globalScale > 0.5) {
190
+ ctx.font = `${fontSize}px Sans-Serif`
191
+ ctx.textAlign = 'center'
192
+ ctx.textBaseline = 'middle'
193
+ ctx.fillStyle = 'rgba(255,255,255,0.85)'
194
+ ctx.fillText(node.name, node.x, node.y + node.val + 8 / globalScale)
195
+ }
196
+ }
197
+ }}
198
+ />
199
+ </div>
200
+ </div>
201
+ )
202
+ }
203
+
204
+ export default SynapticMemoryLobe