@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,516 @@
1
+ import {
2
+ navigateTo,
3
+ readDOM,
4
+ executeAction,
5
+ closeBrowser,
6
+ executeScript,
7
+ extractData,
8
+ takeScreenshot,
9
+ downloadFile,
10
+ showBrowserWindow,
11
+ hideBrowserWindow
12
+ } from '../browser-agent.js'
13
+
14
+ export const browserTools = {
15
+ 'browser-search': {
16
+ needsApproval: false,
17
+ handler: async (args) => {
18
+ try {
19
+ const searchQuery = (
20
+ typeof args === 'object' && args !== null
21
+ ? args.query || args.keyword
22
+ : String(args || '')
23
+ ).trim()
24
+ if (!searchQuery) return { success: false, message: 'Query pencarian kosong.' }
25
+
26
+ let results = []
27
+ const clean = (s) =>
28
+ (s || '')
29
+ .replace(/<[^>]+>/g, '')
30
+ .replace(/&amp;/g, '&')
31
+ .replace(/&quot;/g, '"')
32
+ .replace(/&#39;/g, "'")
33
+ .replace(/&lt;/g, '<')
34
+ .replace(/&gt;/g, '>')
35
+ .replace(/&nbsp;/g, ' ')
36
+ .replace(/&#0183;/g, '·')
37
+ .replace(/\s+/g, ' ')
38
+ .trim()
39
+
40
+ const axios = (await import('axios')).default
41
+
42
+ // 1. Engine 1 (Fresh News): Google News RSS - Selalu update jam & hari ini
43
+ try {
44
+ const newsRes = await axios.get(
45
+ `https://news.google.com/rss/search?q=${encodeURIComponent(searchQuery)}&hl=id&gl=ID&ceid=ID:id`,
46
+ {
47
+ headers: {
48
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
49
+ },
50
+ timeout: 6000
51
+ }
52
+ )
53
+ const xml = newsRes.data || ''
54
+ const items = xml.match(/<item>[\s\S]*?<\/item>/gi) || []
55
+ for (const item of items.slice(0, 4)) {
56
+ const titleMatch = item.match(/<title>([\s\S]*?)<\/title>/i)
57
+ const linkMatch = item.match(/<link>([\s\S]*?)<\/link>/i)
58
+ const pubDateMatch = item.match(/<pubDate>([\s\S]*?)<\/pubDate>/i)
59
+ const descMatch = item.match(/<description>([\s\S]*?)<\/description>/i)
60
+
61
+ if (linkMatch && titleMatch) {
62
+ const dateStr = pubDateMatch ? ` [${clean(pubDateMatch[1])}]` : ''
63
+ results.push({
64
+ title: clean(titleMatch[1]),
65
+ url: clean(linkMatch[1]),
66
+ snippet: clean(descMatch ? descMatch[1] : '') + dateStr
67
+ })
68
+ }
69
+ }
70
+ } catch (_) {}
71
+
72
+ // 2. Engine 2 (Web Results): Bing Search dengan URL Decoder
73
+ if (results.length < 5) {
74
+ try {
75
+ const decodeBingUrl = (url) => {
76
+ if (!url || !url.includes('bing.com/ck/')) return url
77
+ const match = url.match(/[?&]u=a1([^&]+)/i) || url.match(/[?&amp;]u=a1([^&]+)/i)
78
+ if (match) {
79
+ try {
80
+ let b64 = match[1].replace(/-/g, '+').replace(/_/g, '/')
81
+ while (b64.length % 4) b64 += '='
82
+ return Buffer.from(b64, 'base64').toString('utf8')
83
+ } catch (_) {}
84
+ }
85
+ return url
86
+ }
87
+
88
+ const bingRes = await axios.get(
89
+ `https://www.bing.com/search?q=${encodeURIComponent(searchQuery)}&count=10`,
90
+ {
91
+ headers: {
92
+ 'User-Agent':
93
+ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36',
94
+ 'Accept-Language': 'id-ID,id;q=0.9,en-US;q=0.8,en;q=0.7'
95
+ },
96
+ timeout: 7000
97
+ }
98
+ )
99
+ const html = bingRes.data || ''
100
+ const regex = /<li class="b_algo"[\s\S]*?<\/li>/gi
101
+ let match
102
+ while ((match = regex.exec(html)) !== null && results.length < 6) {
103
+ const li = match[0]
104
+ const anchors = [...li.matchAll(/<a[^>]+href="([^"]+)"[^>]*>([\s\S]*?)<\/a>/gi)]
105
+ let realUrl = ''
106
+ let rawTitle = ''
107
+
108
+ for (const a of anchors) {
109
+ const href = a[1]
110
+ const inner = a[2] || ''
111
+ if (href.includes('bing.com/ck/') || href.startsWith('http')) {
112
+ if (!realUrl) realUrl = decodeBingUrl(href)
113
+ if (
114
+ !rawTitle &&
115
+ !inner.includes('class="tpic"') &&
116
+ !inner.includes('class="wr_fav"')
117
+ ) {
118
+ rawTitle = inner
119
+ }
120
+ }
121
+ }
122
+
123
+ const snippetMatch =
124
+ li.match(/<div class="b_caption"[\s\S]*?<p[^>]*>([\s\S]*?)<\/p>/i) ||
125
+ li.match(/<p[^>]*>([\s\S]*?)<\/p>/i)
126
+
127
+ if (
128
+ realUrl &&
129
+ !realUrl.includes('bing.com/search') &&
130
+ !realUrl.endsWith('.css') &&
131
+ !realUrl.endsWith('.js')
132
+ ) {
133
+ const title = clean(rawTitle.includes('›') ? rawTitle.split('›').pop() : rawTitle)
134
+ const snippet = clean(snippetMatch ? snippetMatch[1] : '')
135
+ if (title && !results.some((r) => r.url === realUrl)) {
136
+ results.push({ title: title || 'Web Result', url: realUrl, snippet })
137
+ }
138
+ }
139
+ }
140
+ } catch (_) {}
141
+ }
142
+
143
+ // 3. Engine 3 (Fallback General): Bing RSS Feed
144
+ if (results.length === 0) {
145
+ try {
146
+ const rssRes = await axios.get(
147
+ `https://www.bing.com/search?format=rss&q=${encodeURIComponent(searchQuery)}`,
148
+ {
149
+ headers: {
150
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
151
+ },
152
+ timeout: 7000
153
+ }
154
+ )
155
+ const xml = rssRes.data || ''
156
+ const items = xml.match(/<item>[\s\S]*?<\/item>/gi) || []
157
+ for (const item of items.slice(0, 5)) {
158
+ const titleMatch = item.match(/<title>([\s\S]*?)<\/title>/i)
159
+ const linkMatch = item.match(/<link>([\s\S]*?)<\/link>/i)
160
+ const descMatch = item.match(/<description>([\s\S]*?)<\/description>/i)
161
+ if (linkMatch && titleMatch) {
162
+ results.push({
163
+ title: clean(titleMatch[1]),
164
+ url: clean(linkMatch[1]),
165
+ snippet: clean(descMatch ? descMatch[1] : '')
166
+ })
167
+ }
168
+ }
169
+ } catch (_) {}
170
+ }
171
+
172
+ if (results.length === 0) {
173
+ return {
174
+ success: true,
175
+ data: `Tidak ditemukan link web yang cocok untuk "${searchQuery}". Coba gunakan kata kunci lain.`
176
+ }
177
+ }
178
+
179
+ const formatted = results
180
+ .map(
181
+ (r, idx) =>
182
+ `${idx + 1}. [${r.title}](${r.url})\n Snippet: ${r.snippet ? r.snippet.replace(/\n+/g, ' ') : 'Tidak ada ringkasan.'}`
183
+ )
184
+ .join('\n\n')
185
+
186
+ return {
187
+ success: true,
188
+ data: `[DAFTAR URL HASIL PENCARIAN UNTUK: "${searchQuery}"]\n(Gunakan tool "browser-fetch" dengan parameter url jika kamu ingin membaca isi artikel lengkap dari link di bawah)\n\n${formatted}`
189
+ }
190
+ } catch (err) {
191
+ return { success: false, message: `Gagal melakukan web search: ${err.message}` }
192
+ }
193
+ }
194
+ },
195
+
196
+ 'browser-fetch': {
197
+ needsApproval: false,
198
+ handler: async (args) => {
199
+ let targetUrl = (
200
+ typeof args === 'object' && args !== null ? args.url : String(args || '')
201
+ ).trim()
202
+ const maxChars =
203
+ typeof args === 'object' && args !== null ? parseInt(args.max_chars, 10) || 4000 : 4000
204
+ if (!targetUrl) return { success: false, message: 'URL tujuan tidak boleh kosong.' }
205
+
206
+ if (!targetUrl.startsWith('http://') && !targetUrl.startsWith('https://')) {
207
+ targetUrl = 'https://' + targetUrl
208
+ }
209
+
210
+ try {
211
+ const axios = (await import('axios')).default
212
+ const response = await axios.get(targetUrl, {
213
+ headers: {
214
+ 'User-Agent':
215
+ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36 Edg/133.0.0.0',
216
+ Accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
217
+ 'Accept-Language': 'id-ID,id;q=0.9,en-US;q=0.8,en;q=0.7'
218
+ },
219
+ timeout: 12000,
220
+ maxRedirects: 5
221
+ })
222
+
223
+ const html =
224
+ typeof response.data === 'string' ? response.data : JSON.stringify(response.data)
225
+
226
+ // Bersihkan tag script, style, svg, noscript, nav, footer, header
227
+ let cleanText = html
228
+ .replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '')
229
+ .replace(/<style\b[^<]*(?:(?!<\/style>)<[^<]*)*<\/style>/gi, '')
230
+ .replace(/<svg\b[^<]*(?:(?!<\/svg>)<[^<]*)*<\/svg>/gi, '')
231
+ .replace(/<noscript\b[^<]*(?:(?!<\/noscript>)<[^<]*)*<\/noscript>/gi, '')
232
+ .replace(/<header\b[^<]*(?:(?!<\/header>)<[^<]*)*<\/header>/gi, '')
233
+ .replace(/<footer\b[^<]*(?:(?!<\/footer>)<[^<]*)*<\/footer>/gi, '')
234
+ .replace(/<nav\b[^<]*(?:(?!<\/nav>)<[^<]*)*<\/nav>/gi, '')
235
+ .replace(/<br\s*[\/]?>/gi, '\n')
236
+ .replace(/<\/(p|div|h1|h2|h3|h4|h5|h6|li|tr)>/gi, '\n')
237
+ .replace(/<[^>]+>/g, '')
238
+ .replace(/&amp;/g, '&')
239
+ .replace(/&quot;/g, '"')
240
+ .replace(/&#39;/g, "'")
241
+ .replace(/&lt;/g, '<')
242
+ .replace(/&gt;/g, '>')
243
+ .replace(/&nbsp;/g, ' ')
244
+ .replace(/\t+/g, ' ')
245
+ .replace(/[ ]{2,}/g, ' ')
246
+ .replace(/\n\s*\n\s*\n+/g, '\n\n')
247
+ .trim()
248
+
249
+ if (cleanText.length > maxChars) {
250
+ cleanText =
251
+ cleanText.slice(0, maxChars) +
252
+ `\n\n[...KONTEN DIPOTONG KARENA MELEBIHI ${maxChars} KARAKTER...]`
253
+ }
254
+
255
+ return {
256
+ success: true,
257
+ url: targetUrl,
258
+ data: `[KONTEN HASIL FETCH DARI: ${targetUrl}]\n\n${cleanText || 'Halaman kosong atau hanya berisi elemen grafis/JavaScript dinamis.'}`
259
+ }
260
+ } catch (err) {
261
+ return {
262
+ success: false,
263
+ url: targetUrl,
264
+ error: `Gagal mengambil konten dari ${targetUrl}: ${err.message}. Kamu bisa menggunakan 'browser-navigate' sebagai alternatif.`
265
+ }
266
+ }
267
+ }
268
+ },
269
+
270
+ 'browser-navigate': {
271
+ needsApproval: false,
272
+ handler: async (args, config) => {
273
+ try {
274
+ let url = (typeof args === 'object' && args !== null ? args.url : String(args || '')).trim()
275
+ if (!url.startsWith('http://') && !url.startsWith('https://')) {
276
+ url = 'https://' + url
277
+ }
278
+ const sessionId = config?.sessionId || 'default'
279
+ const result = await navigateTo(url, sessionId)
280
+ return { success: true, data: result }
281
+ } catch (e) {
282
+ return { success: false, error: e.message }
283
+ }
284
+ }
285
+ },
286
+
287
+ 'browser-close': {
288
+ handler: async (args, config) => {
289
+ try {
290
+ const sessionId =
291
+ config?.sessionId ||
292
+ (typeof args === 'object' && args !== null
293
+ ? args.session_id || 'default'
294
+ : String(args || '').trim() || 'default')
295
+ const result = await closeBrowser(sessionId)
296
+ return { success: true, data: result }
297
+ } catch (e) {
298
+ return { success: false, error: e.message }
299
+ }
300
+ }
301
+ },
302
+
303
+ 'browser-show': {
304
+ needsApproval: false,
305
+ handler: async (args, config) => {
306
+ try {
307
+ const sessionId =
308
+ config?.sessionId ||
309
+ (typeof args === 'object' && args !== null
310
+ ? args.session_id || 'default'
311
+ : String(args || '').trim() || 'default')
312
+ const result = await showBrowserWindow(sessionId)
313
+ return { success: true, data: result }
314
+ } catch (e) {
315
+ return { success: false, error: e.message }
316
+ }
317
+ }
318
+ },
319
+
320
+ 'browser-hide': {
321
+ needsApproval: false,
322
+ handler: async (args, config) => {
323
+ try {
324
+ const sessionId =
325
+ config?.sessionId ||
326
+ (typeof args === 'object' && args !== null
327
+ ? args.session_id || 'default'
328
+ : String(args || '').trim() || 'default')
329
+ const result = await hideBrowserWindow(sessionId)
330
+ return { success: true, data: result }
331
+ } catch (e) {
332
+ return { success: false, error: e.message }
333
+ }
334
+ }
335
+ },
336
+
337
+ 'browser-read': {
338
+ needsApproval: false,
339
+ handler: async (_args, config) => {
340
+ try {
341
+ const sessionId = config?.sessionId || 'default'
342
+ const result = await readDOM(sessionId)
343
+ return { success: true, data: result }
344
+ } catch (e) {
345
+ return { success: false, error: e.message }
346
+ }
347
+ }
348
+ },
349
+
350
+ 'browser-click': {
351
+ needsApproval: false,
352
+ handler: async (args, config) => {
353
+ let id = NaN
354
+ if (typeof args === 'object' && args !== null) {
355
+ id = parseInt(args.element_id ?? args.id, 10)
356
+ } else {
357
+ id = parseInt(String(args || '').trim(), 10)
358
+ }
359
+ if (isNaN(id)) return { success: false, error: 'element_id harus berupa angka.' }
360
+ try {
361
+ const sessionId = config?.sessionId || 'default'
362
+ const result = await executeAction({ action: 'click', id }, sessionId)
363
+ return { success: true, data: result }
364
+ } catch (e) {
365
+ return { success: false, error: e.message }
366
+ }
367
+ }
368
+ },
369
+
370
+ 'browser-type': {
371
+ needsApproval: false,
372
+ handler: async (args, config) => {
373
+ let id = NaN
374
+ let text = ''
375
+ if (typeof args === 'object' && args !== null) {
376
+ id = parseInt(args.element_id ?? args.id, 10)
377
+ text = String(args.text ?? '')
378
+ } else {
379
+ const parts = String(args || '').split('||')
380
+ if (parts.length < 2) return { success: false, error: 'Format: ID||teks' }
381
+ id = parseInt(parts[0].trim(), 10)
382
+ text = parts.slice(1).join('||')
383
+ }
384
+ if (isNaN(id)) return { success: false, error: 'element_id harus berupa angka.' }
385
+ try {
386
+ const sessionId = config?.sessionId || 'default'
387
+ const result = await executeAction({ action: 'type', id, value: text }, sessionId)
388
+ return { success: true, data: result }
389
+ } catch (e) {
390
+ return { success: false, error: e.message }
391
+ }
392
+ }
393
+ },
394
+
395
+ 'browser-scroll': {
396
+ needsApproval: false,
397
+ handler: async (args, config) => {
398
+ const direction = (
399
+ typeof args === 'object' && args !== null ? args.direction : String(args || '')
400
+ )
401
+ .trim()
402
+ .toLowerCase()
403
+ if (direction !== 'up' && direction !== 'down') {
404
+ return { success: false, error: "Gunakan 'up' atau 'down'." }
405
+ }
406
+ try {
407
+ const sessionId = config?.sessionId || 'default'
408
+ const result = await executeAction({ action: 'scroll', direction }, sessionId)
409
+ return { success: true, data: result }
410
+ } catch (e) {
411
+ return { success: false, error: e.message }
412
+ }
413
+ }
414
+ },
415
+
416
+ 'browser-ask-user': {
417
+ needsApproval: false,
418
+ handler: async (args, config) => {
419
+ try {
420
+ const prompt =
421
+ typeof args === 'object' && args !== null ? args.prompt || '' : String(args || '')
422
+ const sessionId = config?.sessionId || 'default'
423
+ const result = await executeAction({ action: 'unblock', value: prompt }, sessionId)
424
+ return { success: true, data: result }
425
+ } catch (e) {
426
+ return { success: false, error: e.message }
427
+ }
428
+ }
429
+ },
430
+
431
+ 'browser-script': {
432
+ needsApproval: false,
433
+ handler: async (args, config) => {
434
+ try {
435
+ const script =
436
+ typeof args === 'object' && args !== null ? args.script || '' : String(args || '')
437
+ const sessionId = config?.sessionId || 'default'
438
+ const result = await executeScript(script, sessionId)
439
+ return { success: true, data: result }
440
+ } catch (e) {
441
+ return { success: false, error: e.message }
442
+ }
443
+ }
444
+ },
445
+
446
+ 'browser-extract': {
447
+ needsApproval: false,
448
+ handler: async (args, config) => {
449
+ try {
450
+ const selector =
451
+ typeof args === 'object' && args !== null ? args.selector || '' : String(args || '')
452
+ const sessionId = config?.sessionId || 'default'
453
+ const result = await extractData(selector, sessionId)
454
+ return { success: true, data: result }
455
+ } catch (e) {
456
+ return { success: false, error: e.message }
457
+ }
458
+ }
459
+ },
460
+
461
+ 'browser-screenshot': {
462
+ needsApproval: false,
463
+ handler: async (args, config) => {
464
+ try {
465
+ const filename =
466
+ typeof args === 'object' && args !== null
467
+ ? args.filename || 'screenshot.png'
468
+ : String(args || 'screenshot.png')
469
+ const query = typeof args === 'object' && args !== null ? args.query || null : null
470
+ const sessionId = config?.sessionId || 'default'
471
+ const result = await takeScreenshot(filename, sessionId)
472
+ return {
473
+ success: true,
474
+ data: result.message || `Screenshot berhasil disimpan ke ${result.path}`,
475
+ message: result.message,
476
+ path: result.path,
477
+ dataUrl: result.dataUrl,
478
+ query
479
+ }
480
+ } catch (e) {
481
+ return { success: false, error: e.message }
482
+ }
483
+ }
484
+ },
485
+
486
+ 'browser-download': {
487
+ needsApproval: true,
488
+ approvalMessage: (args) => {
489
+ const url =
490
+ typeof args === 'object' && args !== null
491
+ ? `${args.url} -> ${args.filename}`
492
+ : String(args || '')
493
+ return `Mark ingin mendownload file dari browser:\n\n${url}`
494
+ },
495
+ handler: async (args, config) => {
496
+ let url = ''
497
+ let filename = ''
498
+ if (typeof args === 'object' && args !== null) {
499
+ url = (args.url || '').trim()
500
+ filename = (args.filename || '').trim()
501
+ } else {
502
+ const parts = String(args || '').split('||')
503
+ if (parts.length < 2) return { success: false, error: 'Format: url||filename' }
504
+ url = parts[0].trim()
505
+ filename = parts[1].trim()
506
+ }
507
+ try {
508
+ const sessionId = config?.sessionId || 'default'
509
+ const result = await downloadFile(url, filename, sessionId)
510
+ return { success: true, data: result }
511
+ } catch (e) {
512
+ return { success: false, error: e.message }
513
+ }
514
+ }
515
+ }
516
+ }