@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,328 @@
1
+ /* eslint-disable react/prop-types */
2
+ import { useState, useEffect } from 'react'
3
+ import { createPortal } from 'react-dom'
4
+ import { DiffEditor } from '@monaco-editor/react'
5
+ import { X } from 'lucide-react'
6
+
7
+ function parseToolArgs(tool, query) {
8
+ let parsed = {}
9
+ if (typeof query === 'object' && query !== null) {
10
+ parsed = { ...query }
11
+ } else if (typeof query === 'string') {
12
+ try {
13
+ parsed = JSON.parse(query)
14
+ } catch {
15
+ const parts = query.split('||')
16
+ if (tool === 'write-file') {
17
+ parsed = { path: parts[0]?.trim(), content: parts.slice(1).join('||') }
18
+ } else if (tool === 'replace-content') {
19
+ parsed = {
20
+ path: parts[0]?.trim(),
21
+ target_content: parts[1],
22
+ replacement_content: parts.slice(2).join('||')
23
+ }
24
+ } else if (tool === 'replace-lines') {
25
+ parsed = {
26
+ path: parts[0]?.trim(),
27
+ start_line: parts[1],
28
+ end_line: parts[2],
29
+ new_code: parts.slice(3).join('||')
30
+ }
31
+ } else if (tool === 'delete-file') {
32
+ parsed = { path: parts[0]?.trim() }
33
+ } else {
34
+ parsed = { path: parts[0]?.trim() }
35
+ }
36
+ }
37
+ }
38
+ return parsed
39
+ }
40
+
41
+ function getLanguageFromPath(filePath) {
42
+ if (!filePath) return 'plaintext'
43
+ const ext = filePath.split('.').pop()?.toLowerCase()
44
+ const map = {
45
+ js: 'javascript',
46
+ jsx: 'javascript',
47
+ ts: 'typescript',
48
+ tsx: 'typescript',
49
+ json: 'json',
50
+ html: 'html',
51
+ css: 'css',
52
+ scss: 'scss',
53
+ less: 'less',
54
+ md: 'markdown',
55
+ py: 'python',
56
+ sh: 'shell',
57
+ bash: 'shell',
58
+ ps1: 'powershell',
59
+ sql: 'sql',
60
+ yaml: 'yaml',
61
+ yml: 'yaml',
62
+ xml: 'xml',
63
+ rs: 'rust',
64
+ go: 'go',
65
+ java: 'java',
66
+ c: 'c',
67
+ cpp: 'cpp',
68
+ cs: 'csharp',
69
+ php: 'php'
70
+ }
71
+ return map[ext] || 'plaintext'
72
+ }
73
+
74
+ export const FileDiffModal = ({ isOpen = false, onClose, tool = '', query = null, onResolve }) => {
75
+ const [loading, setLoading] = useState(true)
76
+ const [originalContent, setOriginalContent] = useState('')
77
+ const [modifiedContent, setModifiedContent] = useState('')
78
+ const [filePath, setFilePath] = useState('')
79
+ const [isNewFile, setIsNewFile] = useState(false)
80
+ const [errorMessage, setErrorMessage] = useState('')
81
+ const isViewOnly = !onResolve || tool === 'read-file' || tool === 'view-artifact'
82
+
83
+ useEffect(() => {
84
+ if (!isOpen) return
85
+
86
+ let isMounted = true
87
+
88
+ const loadDiff = async () => {
89
+ setLoading(true)
90
+ setErrorMessage('')
91
+ try {
92
+ const parsed = parseToolArgs(tool, query)
93
+ const targetPath = (parsed.path || parsed.filePath || parsed.target || '').trim()
94
+ setFilePath(targetPath)
95
+
96
+ if (!targetPath) {
97
+ if (isMounted) {
98
+ setErrorMessage('Path file tidak ditemukan dalam argumen tool.')
99
+ setLoading(false)
100
+ }
101
+ return
102
+ }
103
+
104
+ let original = ''
105
+ let exists = true
106
+
107
+ if (window.api?.executeNativeTool) {
108
+ const res = await window.api.executeNativeTool('read-file', {
109
+ path: targetPath,
110
+ raw: true
111
+ })
112
+ if (res && res.success) {
113
+ original = res.content || ''
114
+ exists = res.exists !== false
115
+ } else if (res && res.exists === false) {
116
+ original = ''
117
+ exists = false
118
+ }
119
+ }
120
+
121
+ let modified = original
122
+ if (tool === 'write-file') {
123
+ modified =
124
+ typeof parsed.content === 'string'
125
+ ? parsed.content
126
+ : JSON.stringify(parsed.content ?? '', null, 2)
127
+ } else if (tool === 'replace-content') {
128
+ const target = parsed.target_content ?? ''
129
+ const replacement = parsed.replacement_content ?? ''
130
+ if (original.includes(target)) {
131
+ modified = original.replace(target, replacement)
132
+ } else {
133
+ modified = original
134
+ }
135
+ } else if (tool === 'replace-lines') {
136
+ const startLine = parseInt(parsed.start_line, 10)
137
+ const endLine = parseInt(parsed.end_line, 10)
138
+ const newCode = parsed.new_code !== undefined ? parsed.new_code : parsed.content || ''
139
+ const lines = original.split('\n')
140
+ if (
141
+ !isNaN(startLine) &&
142
+ !isNaN(endLine) &&
143
+ startLine >= 1 &&
144
+ startLine <= lines.length &&
145
+ endLine >= startLine
146
+ ) {
147
+ lines.splice(startLine - 1, endLine - startLine + 1, newCode)
148
+ modified = lines.join('\n')
149
+ }
150
+ } else if (tool === 'delete-file') {
151
+ modified = ''
152
+ }
153
+
154
+ if (isMounted) {
155
+ setOriginalContent(original)
156
+ setModifiedContent(modified)
157
+ setIsNewFile(!exists)
158
+ setLoading(false)
159
+ }
160
+ } catch (err) {
161
+ if (isMounted) {
162
+ setErrorMessage(`Gagal memuat perbandingan berkas: ${err.message}`)
163
+ setLoading(false)
164
+ }
165
+ }
166
+ }
167
+
168
+ loadDiff()
169
+
170
+ return () => {
171
+ isMounted = false
172
+ }
173
+ }, [isOpen, tool, query])
174
+
175
+ if (!isOpen) return null
176
+
177
+ const language = getLanguageFromPath(filePath)
178
+ const fileName = filePath
179
+ ? filePath
180
+ .replace(/[\\/]+/g, '/')
181
+ .split('/')
182
+ .pop()
183
+ : ''
184
+
185
+ const modalContent = (
186
+ <div
187
+ className="fixed inset-0 z-[999999] flex items-center justify-center bg-black/75 backdrop-blur-sm p-4 sm:p-6 animate-[response-fade-in_0.15s_ease-out_forwards]"
188
+ onClick={onClose}
189
+ >
190
+ <div
191
+ className="bg-base-300 border border-white/10 rounded-xl shadow-2xl flex flex-col w-[94vw] max-w-5xl h-[85vh] overflow-hidden text-sm"
192
+ onClick={(e) => e.stopPropagation()}
193
+ >
194
+ {/* Header Informative */}
195
+ <div className="flex items-center justify-between px-4 py-3 bg-base-200/90 border-b border-white/10 shrink-0">
196
+ <div className="flex items-center gap-2.5 min-w-0">
197
+ <span className="font-semibold text-white truncate text-xs sm:text-sm">
198
+ Review Perubahan Berkas: {fileName}
199
+ </span>
200
+ {filePath && (
201
+ <span
202
+ className="text-[11px] font-mono text-white/40 truncate hidden sm:inline"
203
+ title={filePath}
204
+ >
205
+ ({filePath})
206
+ </span>
207
+ )}
208
+ {isViewOnly ? (
209
+ <span className="bg-primary/20 text-primary border border-primary/30 px-2 py-0.5 rounded text-[11px] font-mono shrink-0">
210
+ Artefak Tahap
211
+ </span>
212
+ ) : (
213
+ <>
214
+ {tool && (
215
+ <span className="bg-white/10 text-white/80 px-2 py-0.5 rounded text-[11px] font-mono shrink-0">
216
+ {tool}
217
+ </span>
218
+ )}
219
+ {isNewFile && (
220
+ <span className="bg-success/15 text-success px-2 py-0.5 rounded text-[11px] font-semibold shrink-0">
221
+ Berkas Baru
222
+ </span>
223
+ )}
224
+ {tool === 'delete-file' && (
225
+ <span className="bg-error/15 text-error px-2 py-0.5 rounded text-[11px] font-semibold shrink-0">
226
+ Hapus Berkas
227
+ </span>
228
+ )}
229
+ </>
230
+ )}
231
+ </div>
232
+ <button
233
+ type="button"
234
+ onClick={onClose}
235
+ className="btn btn-ghost btn-xs btn-circle text-white/60 hover:text-white"
236
+ title="Tutup"
237
+ >
238
+ <X className="w-4 h-4" />
239
+ </button>
240
+ </div>
241
+
242
+ {/* Diff Content Area */}
243
+ <div className="flex-1 relative overflow-hidden bg-[#1e1e1e]">
244
+ {loading ? (
245
+ <div className="absolute inset-0 flex items-center justify-center gap-2 text-white/60 text-xs font-mono">
246
+ <span className="loading loading-spinner loading-sm text-primary" />
247
+ <span>Memuat perbandingan berkas...</span>
248
+ </div>
249
+ ) : errorMessage ? (
250
+ <div className="absolute inset-0 flex items-center justify-center p-4 text-error text-xs font-mono">
251
+ {errorMessage}
252
+ </div>
253
+ ) : (
254
+ <DiffEditor
255
+ height="100%"
256
+ original={originalContent}
257
+ modified={modifiedContent}
258
+ language={language}
259
+ theme="vs-dark"
260
+ options={{
261
+ readOnly: true,
262
+ renderSideBySide: !isViewOnly,
263
+ minimap: { enabled: false },
264
+ fontSize: 12,
265
+ lineNumbers: 'on',
266
+ wordWrap: 'on',
267
+ automaticLayout: true,
268
+ scrollBeyondLastLine: false,
269
+ padding: { top: 8, bottom: 8 }
270
+ }}
271
+ />
272
+ )}
273
+ </div>
274
+
275
+ {/* Footer Informative Actions */}
276
+ <div className="flex flex-wrap items-center justify-end px-4 py-3 bg-base-200/90 border-t border-white/10 shrink-0 gap-2">
277
+ {isViewOnly ? (
278
+ <div className="flex items-center gap-2">
279
+ <button
280
+ type="button"
281
+ onClick={onClose}
282
+ className="btn btn-primary btn-sm text-black font-semibold rounded-lg px-4 shadow-sm"
283
+ >
284
+ Tutup Pratinjau
285
+ </button>
286
+ </div>
287
+ ) : (
288
+ <div className="flex items-center gap-2">
289
+ <button
290
+ type="button"
291
+ onClick={() => onResolve && onResolve('reject')}
292
+ className="btn btn-ghost btn-sm text-error/80 hover:text-error hover:bg-error/10 rounded-lg px-3"
293
+ >
294
+ Tolak
295
+ </button>
296
+ <button
297
+ type="button"
298
+ onClick={() => onResolve && onResolve('approve_session')}
299
+ className="btn btn-ghost btn-sm text-warning/80 hover:text-warning hover:bg-warning/10 rounded-lg px-3"
300
+ >
301
+ Izinkan Sesi Ini
302
+ </button>
303
+ <button
304
+ type="button"
305
+ onClick={() => onResolve && onResolve('approve_always')}
306
+ className="btn btn-ghost btn-sm text-white/40 hover:text-error hover:bg-error/10 rounded-lg px-3"
307
+ >
308
+ Izinkan Selamanya
309
+ </button>
310
+ <button
311
+ type="button"
312
+ onClick={() => onResolve && onResolve('approve_once')}
313
+ className="btn btn-primary btn-sm text-black font-semibold rounded-lg px-4 shadow-sm"
314
+ >
315
+ Izinkan Sekali
316
+ </button>
317
+ </div>
318
+ )}
319
+ </div>
320
+ </div>
321
+ </div>
322
+ )
323
+
324
+ if (typeof document === 'undefined') return null
325
+ return createPortal(modalContent, document.body)
326
+ }
327
+
328
+ export default FileDiffModal
@@ -0,0 +1,82 @@
1
+ import React from 'react'
2
+
3
+ /**
4
+ * <FollowUp label="..." query="..." />
5
+ * Komponen chip saran pertanyaan lanjutan
6
+ */
7
+ export const FollowUp = React.memo(({ label, query, children, onClick }) => {
8
+ const displayLabel = label || children || query
9
+ if (!displayLabel) return null
10
+
11
+ return (
12
+ <button
13
+ type="button"
14
+ onClick={() => onClick && onClick(query || displayLabel)}
15
+ className="px-2.5 py-1 rounded-lg text-xs bg-white/5 hover:bg-primary/20 text-white/90 hover:text-primary border border-white/10 hover:border-primary/40 transition-all cursor-pointer text-left font-sans shadow-sm active:scale-95"
16
+ title={query || displayLabel}
17
+ >
18
+ {displayLabel}
19
+ </button>
20
+ )
21
+ })
22
+
23
+ /**
24
+ * <Suggestion label="..." query="..." />
25
+ * Komponen chip saran aksi/eksplorasi alternatif
26
+ */
27
+ export const Suggestion = React.memo(({ label, query, children, onClick }) => {
28
+ const displayLabel = label || children || query
29
+ if (!displayLabel) return null
30
+
31
+ return (
32
+ <button
33
+ type="button"
34
+ onClick={() => onClick && onClick(query || displayLabel)}
35
+ className="px-2.5 py-1 rounded-lg text-xs bg-white/5 hover:bg-primary/20 text-white/90 hover:text-primary border border-white/10 hover:border-primary/40 transition-all cursor-pointer text-left font-sans shadow-sm active:scale-95"
36
+ title={query || displayLabel}
37
+ >
38
+ {displayLabel}
39
+ </button>
40
+ )
41
+ })
42
+
43
+ /**
44
+ * <Elicitation label="..." query="..." />
45
+ * Komponen opsi jawaban/klarifikasi di dalam ElicitationsGroup
46
+ */
47
+ export const Elicitation = React.memo(({ label, query, children, onClick }) => {
48
+ const displayLabel = label || children || query
49
+ if (!displayLabel) return null
50
+
51
+ return (
52
+ <button
53
+ type="button"
54
+ onClick={() => onClick && onClick(query || displayLabel)}
55
+ className="px-3 py-1.5 rounded-lg text-xs bg-primary/10 hover:bg-primary/25 text-primary border border-primary/30 hover:border-primary/60 transition-all cursor-pointer text-left font-sans shadow-sm active:scale-95 font-medium"
56
+ title={query || displayLabel}
57
+ >
58
+ {displayLabel}
59
+ </button>
60
+ )
61
+ })
62
+
63
+ /**
64
+ * <ElicitationsGroup message="..."> ... </ElicitationsGroup>
65
+ * Kontainer grup klarifikasi ketika percakapan butuh percabangan pilihan
66
+ */
67
+ export const ElicitationsGroup = React.memo(({ message, children }) => {
68
+ if (!children) return null
69
+
70
+ return (
71
+ <div className="mt-2 pt-2.5 border-t border-white/10 flex flex-col gap-2 animate-fade-in bg-base-300/40 p-2.5 rounded-xl border border-white/5">
72
+ {message && (
73
+ <span className="text-xs font-semibold text-primary">
74
+ {message}
75
+ </span>
76
+ )}
77
+ <div className="flex flex-wrap gap-1.5">
78
+ {children}
79
+ </div>
80
+ </div>
81
+ )
82
+ })
@@ -0,0 +1,34 @@
1
+ import React from 'react'
2
+ import { Database, PlusCircle, Edit3, Trash2 } from 'lucide-react'
3
+
4
+ export const MemoryFooterBubble = ({
5
+ isMemorySaved = false,
6
+ isMemoryUpdated = false,
7
+ isMemoryDeleted = false
8
+ }) => {
9
+ if (!isMemorySaved && !isMemoryUpdated && !isMemoryDeleted) return null
10
+
11
+ return (
12
+ <div className="flex items-center gap-1.5 mt-1 px-1 text-[10px] font-medium opacity-80 select-none">
13
+ <Database className="w-3 h-3 text-secondary" />
14
+ {isMemorySaved && (
15
+ <span className="text-success flex items-center gap-1">
16
+ <PlusCircle className="w-2.5 h-2.5" />
17
+ Memori baru tersimpan
18
+ </span>
19
+ )}
20
+ {isMemoryUpdated && (
21
+ <span className="text-info flex items-center gap-1">
22
+ <Edit3 className="w-2.5 h-2.5" />
23
+ Memori diperbarui
24
+ </span>
25
+ )}
26
+ {isMemoryDeleted && (
27
+ <span className="text-error flex items-center gap-1">
28
+ <Trash2 className="w-2.5 h-2.5" />
29
+ Memori dihapus
30
+ </span>
31
+ )}
32
+ </div>
33
+ )
34
+ }