@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.
- package/LICENSE +29 -0
- package/README.md +209 -0
- package/bin/mark.js +27 -0
- package/out/renderer/assets/icon-DHo2CYph.svg +1 -0
- package/out/renderer/assets/index-G2fADWO-.js +4768 -0
- package/out/renderer/assets/index-f3mVse3c.css +1 -0
- package/out/renderer/assets/music-cover-CG4vi3kZ.png +0 -0
- package/out/renderer/assets/poppins-devanagari-400-normal-CJDn6rn8.woff2 +0 -0
- package/out/renderer/assets/poppins-devanagari-400-normal-CqVvlrh5.woff +0 -0
- package/out/renderer/assets/poppins-devanagari-500-normal-BIdkeU1p.woff2 +0 -0
- package/out/renderer/assets/poppins-devanagari-500-normal-DMPDjHtT.woff +0 -0
- package/out/renderer/assets/poppins-devanagari-600-normal-ClASKHrr.woff +0 -0
- package/out/renderer/assets/poppins-devanagari-600-normal-STEjXBNN.woff2 +0 -0
- package/out/renderer/assets/poppins-devanagari-700-normal-O-jipLrW.woff2 +0 -0
- package/out/renderer/assets/poppins-devanagari-700-normal-fHs-vx92.woff +0 -0
- package/out/renderer/assets/poppins-latin-400-normal-BOb3E3N0.woff +0 -0
- package/out/renderer/assets/poppins-latin-400-normal-cpxAROuN.woff2 +0 -0
- package/out/renderer/assets/poppins-latin-500-normal-C8OXljZJ.woff2 +0 -0
- package/out/renderer/assets/poppins-latin-500-normal-DGXqpDMm.woff +0 -0
- package/out/renderer/assets/poppins-latin-600-normal-BJdTmd5m.woff +0 -0
- package/out/renderer/assets/poppins-latin-600-normal-zEkxB9Mr.woff2 +0 -0
- package/out/renderer/assets/poppins-latin-700-normal-BVuQR_eA.woff +0 -0
- package/out/renderer/assets/poppins-latin-700-normal-Qrb0O0WB.woff2 +0 -0
- package/out/renderer/assets/poppins-latin-ext-400-normal-DaBSavcJ.woff +0 -0
- package/out/renderer/assets/poppins-latin-ext-400-normal-by3JarPu.woff2 +0 -0
- package/out/renderer/assets/poppins-latin-ext-500-normal-CK-6C4Hw.woff2 +0 -0
- package/out/renderer/assets/poppins-latin-ext-500-normal-CgAe2rWW.woff +0 -0
- package/out/renderer/assets/poppins-latin-ext-600-normal-CAhIAdZj.woff2 +0 -0
- package/out/renderer/assets/poppins-latin-ext-600-normal-Df5ffKXP.woff +0 -0
- package/out/renderer/assets/poppins-latin-ext-700-normal-DctTR6Tg.woff +0 -0
- package/out/renderer/assets/poppins-latin-ext-700-normal-cby-RkWa.woff2 +0 -0
- package/out/renderer/favicon.ico +0 -0
- package/out/renderer/icon-256.png +0 -0
- package/out/renderer/icon.svg +1 -0
- package/out/renderer/index.html +25 -0
- package/out/renderer/manifest.json +25 -0
- package/out/renderer/robot-simulator.html +1640 -0
- package/package.json +106 -0
- package/src/cli/index.js +332 -0
- package/src/cli/monitor.js +413 -0
- package/src/cli/theme.js +347 -0
- package/src/launcher/MarkTray.cs +227 -0
- package/src/main/browser-agent.js +1132 -0
- package/src/main/git-service.js +90 -0
- package/src/main/google/google-calendar.js +69 -0
- package/src/main/google/google-drive.js +263 -0
- package/src/main/google/google-gmail.js +131 -0
- package/src/main/google/google-service.js +241 -0
- package/src/main/node-tools.js +23 -0
- package/src/main/pc-agent-scripts/mouse-locker.ps1 +76 -0
- package/src/main/pc-agent-scripts/ocr-region.ps1 +185 -0
- package/src/main/pc-agent-scripts/pc-daemon.ps1 +726 -0
- package/src/main/pc-agent-scripts/pc-overlay.ps1 +253 -0
- package/src/main/pc-agent-scripts/pick-folder.ps1 +33 -0
- package/src/main/pc-agent-scripts/read-ui.ps1 +181 -0
- package/src/main/pc-agent-scripts/take-screenshot.ps1 +24 -0
- package/src/main/pc-agent-scripts/win-action.ps1 +380 -0
- package/src/main/plugins/plugin-loader.js +306 -0
- package/src/main/skills/skill-manager.js +265 -0
- package/src/main/syntax-validator.js +455 -0
- package/src/main/task-daemon.js +117 -0
- package/src/main/telegram/telegram-service.js +835 -0
- package/src/main/tools/browser-tools.js +516 -0
- package/src/main/tools/file-tools.js +1126 -0
- package/src/main/tools/git-tools.js +79 -0
- package/src/main/tools/google-tools.js +566 -0
- package/src/main/tools/index.js +36 -0
- package/src/main/tools/media-tools.js +42 -0
- package/src/main/tools/system-tools.js +295 -0
- package/src/main/tools/task-tools.js +73 -0
- package/src/main/tools/telegram-tools.js +101 -0
- package/src/renderer/index.html +24 -0
- package/src/renderer/public/favicon.ico +0 -0
- package/src/renderer/public/icon-256.png +0 -0
- package/src/renderer/public/icon.svg +1 -0
- package/src/renderer/public/manifest.json +25 -0
- package/src/renderer/public/robot-simulator.html +1640 -0
- package/src/renderer/src/App.jsx +304 -0
- package/src/renderer/src/api/ai/awareness.js +294 -0
- package/src/renderer/src/api/ai/chatSummarizer.js +79 -0
- package/src/renderer/src/api/ai/contextCompactor.js +129 -0
- package/src/renderer/src/api/ai/contextManager.js +1130 -0
- package/src/renderer/src/api/ai/core.js +167 -0
- package/src/renderer/src/api/ai/index.js +4 -0
- package/src/renderer/src/api/ai/memoryGroomer.js +101 -0
- package/src/renderer/src/api/ai/persona.js +115 -0
- package/src/renderer/src/api/ai/planning.js +317 -0
- package/src/renderer/src/api/ai/relationship.js +177 -0
- package/src/renderer/src/api/ai/skillSynthesizer.js +168 -0
- package/src/renderer/src/api/ai/tools.js +167 -0
- package/src/renderer/src/api/ai/utils.js +359 -0
- package/src/renderer/src/api/db.js +1013 -0
- package/src/renderer/src/api/oramaStore.js +592 -0
- package/src/renderer/src/api/ragPipeline.js +87 -0
- package/src/renderer/src/api/subagent/subagentExecutor.js +780 -0
- package/src/renderer/src/api/subagent/subagentPrompt.js +44 -0
- package/src/renderer/src/api/subagent/subagentStore.js +173 -0
- package/src/renderer/src/api/taskExecutor.js +18 -0
- package/src/renderer/src/api/taskStore.js +315 -0
- package/src/renderer/src/api/tools/core-tools.js +707 -0
- package/src/renderer/src/api/tools/index.js +151 -0
- package/src/renderer/src/api/turnPairMigrator.js +200 -0
- package/src/renderer/src/api/vectorMemory.js +136 -0
- package/src/renderer/src/api/wakeWord.js +101 -0
- package/src/renderer/src/api/web-bridge.js +885 -0
- package/src/renderer/src/api/webSpeech.js +178 -0
- package/src/renderer/src/api/workspaceRag.js +76 -0
- package/src/renderer/src/assets/electron.svg +10 -0
- package/src/renderer/src/assets/icon.svg +1 -0
- package/src/renderer/src/assets/main.css +589 -0
- package/src/renderer/src/assets/music-cover.png +0 -0
- package/src/renderer/src/assets/wavy-lines.svg +25 -0
- package/src/renderer/src/components/Chat/ApprovalBubble.jsx +127 -0
- package/src/renderer/src/components/Chat/CodeBlock.jsx +83 -0
- package/src/renderer/src/components/Chat/DurableTaskBubble.jsx +455 -0
- package/src/renderer/src/components/Chat/FileDiffModal.jsx +328 -0
- package/src/renderer/src/components/Chat/GeminiWidgets.jsx +82 -0
- package/src/renderer/src/components/Chat/MemoryFooterBubble.jsx +34 -0
- package/src/renderer/src/components/Chat/MessageBubble.jsx +459 -0
- package/src/renderer/src/components/Chat/PluginExecutionBubble.jsx +41 -0
- package/src/renderer/src/components/Chat/ThinkingBubble.jsx +316 -0
- package/src/renderer/src/components/Chat/YoutubeSearchBubble.jsx +43 -0
- package/src/renderer/src/components/Chat/YoutubeSummaryBubble.jsx +40 -0
- package/src/renderer/src/components/Chat/index.js +11 -0
- package/src/renderer/src/components/ChatList.jsx +434 -0
- package/src/renderer/src/components/GlobalCameraManager.jsx +67 -0
- package/src/renderer/src/components/Versions.jsx +15 -0
- package/src/renderer/src/components/YoutubeMusicPlayer.jsx +375 -0
- package/src/renderer/src/components/camera/CameraPreview.jsx +236 -0
- package/src/renderer/src/components/config/AiEngineSection.jsx +363 -0
- package/src/renderer/src/components/config/CameraSection.jsx +100 -0
- package/src/renderer/src/components/config/PermissionsSection.jsx +130 -0
- package/src/renderer/src/components/config/ShortcutSection.jsx +102 -0
- package/src/renderer/src/components/config/VoiceSection.jsx +110 -0
- package/src/renderer/src/components/config/index.js +5 -0
- package/src/renderer/src/components/core/Avatar.jsx +2197 -0
- package/src/renderer/src/components/core/ConfirmModal.jsx +80 -0
- package/src/renderer/src/components/core/DraggableHoloCard.jsx +125 -0
- package/src/renderer/src/components/core/FloatingMenu.jsx +272 -0
- package/src/renderer/src/components/core/HoloCard.jsx +64 -0
- package/src/renderer/src/components/core/InputBar.jsx +1346 -0
- package/src/renderer/src/components/core/ProcessPanel.jsx +216 -0
- package/src/renderer/src/components/core/ResponseArea.jsx +149 -0
- package/src/renderer/src/components/core/StatusIndicator.jsx +59 -0
- package/src/renderer/src/components/core/ThoughtNeuralFlow.jsx +168 -0
- package/src/renderer/src/components/core/ToolClustersDeck.jsx +210 -0
- package/src/renderer/src/components/core/native-skills.js +43 -0
- package/src/renderer/src/components/neural-core/EmotionalCortexLobe.jsx +359 -0
- package/src/renderer/src/components/neural-core/NodeDissectionModal.jsx +57 -0
- package/src/renderer/src/components/neural-core/ProceduralMatrixLobe.jsx +193 -0
- package/src/renderer/src/components/neural-core/ProceduralSkillModal.jsx +53 -0
- package/src/renderer/src/components/neural-core/ResetAiModal.jsx +198 -0
- package/src/renderer/src/components/neural-core/SynapticMemoryLobe.jsx +204 -0
- package/src/renderer/src/components/neural-core/traitMeta.js +102 -0
- package/src/renderer/src/components/subagent/AgentChatFeed.jsx +603 -0
- package/src/renderer/src/components/subagent/AgentInspector.jsx +224 -0
- package/src/renderer/src/components/subagent/AgentSidebar.jsx +216 -0
- package/src/renderer/src/components/subagent/SubagentIntercom.jsx +572 -0
- package/src/renderer/src/components/subagent/SubagentTopologyMap.jsx +423 -0
- package/src/renderer/src/contexts/ApprovalContext.jsx +425 -0
- package/src/renderer/src/contexts/ChatContext.jsx +61 -0
- package/src/renderer/src/contexts/YoutubeMusicContext.jsx +333 -0
- package/src/renderer/src/data/faqData.js +202 -0
- package/src/renderer/src/hooks/agent/executeAgentTool.js +895 -0
- package/src/renderer/src/hooks/agent/index.js +4 -0
- package/src/renderer/src/hooks/agent/useMarkMusic.js +75 -0
- package/src/renderer/src/hooks/agent/useMarkPlan.js +2739 -0
- package/src/renderer/src/hooks/agent/useMarkState.js +173 -0
- package/src/renderer/src/hooks/agent/useMarkYoutube.js +82 -0
- package/src/renderer/src/hooks/agent/useRelationalGrowth.js +201 -0
- package/src/renderer/src/hooks/telegram/useTelegramBot.js +63 -0
- package/src/renderer/src/hooks/useAwareness.js +289 -0
- package/src/renderer/src/hooks/useChatArchiver.js +52 -0
- package/src/renderer/src/hooks/useConfirm.jsx +68 -0
- package/src/renderer/src/hooks/useMarkAgent.js +454 -0
- package/src/renderer/src/hooks/useMemoryGroomer.js +152 -0
- package/src/renderer/src/hooks/useVAD.js +511 -0
- package/src/renderer/src/hooks/useWebSpeechWakeWord.js +122 -0
- package/src/renderer/src/main.jsx +12 -0
- package/src/renderer/src/pages/ChatStudio.jsx +922 -0
- package/src/renderer/src/pages/Configuration.jsx +360 -0
- package/src/renderer/src/pages/GoogleWorkspace.jsx +293 -0
- package/src/renderer/src/pages/Guidebook.jsx +917 -0
- package/src/renderer/src/pages/Knowledge.jsx +241 -0
- package/src/renderer/src/pages/MarkHome.jsx +491 -0
- package/src/renderer/src/pages/NeuralCore.jsx +786 -0
- package/src/renderer/src/pages/Plugins.jsx +630 -0
- package/src/renderer/src/pages/SkillEditor.jsx +380 -0
- package/src/renderer/src/pages/Skills.jsx +219 -0
- package/src/renderer/src/pages/Subagents.jsx +342 -0
- package/src/renderer/src/pages/TelegramBot.jsx +343 -0
- package/src/renderer/src/utils/chatContentParser.js +203 -0
- package/src/renderer/src/utils/toolClusters.js +201 -0
- package/src/server/bin/sha3_wasm_bg.wasm +0 -0
- package/src/server/config-manager.js +57 -0
- package/src/server/index.js +195 -0
- package/src/server/launcher.js +87 -0
- package/src/server/memory/db-store.js +758 -0
- package/src/server/memory/orama-store.js +177 -0
- package/src/server/memory/vector-engine.js +109 -0
- package/src/server/routes/ai.routes.js +280 -0
- package/src/server/routes/awareness.routes.js +62 -0
- package/src/server/routes/chat.routes.js +61 -0
- package/src/server/routes/config.routes.js +41 -0
- package/src/server/routes/index.js +35 -0
- package/src/server/routes/integrations.routes.js +116 -0
- package/src/server/routes/memory.routes.js +256 -0
- package/src/server/routes/plugins.routes.js +72 -0
- package/src/server/routes/skills.routes.js +139 -0
- package/src/server/routes/subagents.routes.js +70 -0
- package/src/server/routes/tasks.routes.js +175 -0
- package/src/server/routes/workspace.routes.js +127 -0
- package/src/server/services/ai/ai-utils.js +161 -0
- package/src/server/services/ai/openai-provider.js +757 -0
- package/src/server/services/ai/web-provider.js +729 -0
- package/src/server/services/ai-bridge.js +46 -0
- package/src/server/services/deepseek-web.js +956 -0
- package/src/server/services/gemini-web.js +170 -0
- package/src/server/services/notification-service.js +91 -0
- package/src/server/services/updater.js +125 -0
- package/src/server/tools/awareness-tracker.js +292 -0
- package/src/server/tools/group-tools.js +1164 -0
- package/src/server/tools/media-tools.js +244 -0
- package/src/server/tools/pc-agent.js +327 -0
- package/src/server/tools/screen-service.js +51 -0
- package/src/server/ws-hub.js +168 -0
- package/src/shared/parsers/mark-tag-parser.js +275 -0
|
@@ -0,0 +1,885 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Web Bridge Adapter untuk MARK WebUI.
|
|
3
|
+
* Menghubungkan antarmuka React secara langsung ke Node.js Core Backend via REST API & WebSocket.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const isBrowser =
|
|
7
|
+
typeof window !== 'undefined' &&
|
|
8
|
+
window.location?.origin &&
|
|
9
|
+
!window.location.origin.startsWith('file:')
|
|
10
|
+
|
|
11
|
+
export const SERVER_CONFIG = {
|
|
12
|
+
host:
|
|
13
|
+
typeof window !== 'undefined' && window.location?.hostname
|
|
14
|
+
? window.location.hostname
|
|
15
|
+
: 'localhost',
|
|
16
|
+
port:
|
|
17
|
+
typeof window !== 'undefined' && window.location?.port
|
|
18
|
+
? Number(window.location.port) || 3000
|
|
19
|
+
: 3000,
|
|
20
|
+
apiBase: isBrowser ? window.location.origin : 'http://localhost:3000',
|
|
21
|
+
wsProtocol: isBrowser && window.location.protocol === 'https:' ? 'wss:' : 'ws:',
|
|
22
|
+
wsHost: isBrowser ? window.location.host : 'localhost:3000',
|
|
23
|
+
get wsBase() {
|
|
24
|
+
return `${this.wsProtocol}//${this.wsHost}/stream`
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export const SERVER_HOST = SERVER_CONFIG.host
|
|
29
|
+
export const SERVER_PORT = SERVER_CONFIG.port
|
|
30
|
+
export const API_BASE = SERVER_CONFIG.apiBase
|
|
31
|
+
export const WS_PROTOCOL = SERVER_CONFIG.wsProtocol
|
|
32
|
+
export const WS_HOST = SERVER_CONFIG.wsHost
|
|
33
|
+
export const WS_BASE = SERVER_CONFIG.wsBase
|
|
34
|
+
|
|
35
|
+
let ws = null
|
|
36
|
+
const listeners = new Map()
|
|
37
|
+
|
|
38
|
+
function getWebSocket() {
|
|
39
|
+
if (typeof window === 'undefined') return null
|
|
40
|
+
if (ws && (ws.readyState === WebSocket.OPEN || ws.readyState === WebSocket.CONNECTING)) {
|
|
41
|
+
return ws
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
try {
|
|
45
|
+
ws = new WebSocket(WS_BASE)
|
|
46
|
+
|
|
47
|
+
ws.onopen = () => {
|
|
48
|
+
console.log('[WebBridge] Terhubung ke WebSocket MARK Core di', WS_BASE)
|
|
49
|
+
try {
|
|
50
|
+
ws.send(JSON.stringify({ event: 'ui:presence', payload: { client: 'webui' } }))
|
|
51
|
+
} catch (_) {}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
ws.onmessage = (event) => {
|
|
55
|
+
try {
|
|
56
|
+
const data = JSON.parse(event.data)
|
|
57
|
+
const { event: evtName, payload } = data
|
|
58
|
+
|
|
59
|
+
if (evtName && listeners.has(evtName)) {
|
|
60
|
+
listeners.get(evtName).forEach((cb) => {
|
|
61
|
+
try {
|
|
62
|
+
cb(payload)
|
|
63
|
+
} catch (err) {
|
|
64
|
+
console.error(`[WebBridge] Error pada listener event '${evtName}':`, err)
|
|
65
|
+
}
|
|
66
|
+
})
|
|
67
|
+
}
|
|
68
|
+
} catch (err) {
|
|
69
|
+
console.error('[WebBridge] Gagal parse pesan WebSocket:', err)
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
ws.onclose = () => {
|
|
74
|
+
console.warn('[WebBridge] Koneksi WebSocket terputus. Mencoba reconnect dalam 3 detik...')
|
|
75
|
+
setTimeout(getWebSocket, 3000)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
ws.onerror = (err) => {
|
|
79
|
+
console.error('[WebBridge] WebSocket error:', err)
|
|
80
|
+
}
|
|
81
|
+
} catch (err) {
|
|
82
|
+
console.error('[WebBridge] Gagal membuat WebSocket:', err)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return ws
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function addWebListener(event, callback) {
|
|
89
|
+
if (!listeners.has(event)) {
|
|
90
|
+
listeners.set(event, new Set())
|
|
91
|
+
}
|
|
92
|
+
listeners.get(event).add(callback)
|
|
93
|
+
getWebSocket()
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function removeWebListener(event, callback) {
|
|
97
|
+
if (listeners.has(event)) {
|
|
98
|
+
listeners.get(event).delete(callback)
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export function removeAllWebListeners(event) {
|
|
103
|
+
if (listeners.has(event)) {
|
|
104
|
+
listeners.get(event).clear()
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export function resolveAbortSignal(sig) {
|
|
109
|
+
if (!sig) return undefined
|
|
110
|
+
if (typeof AbortSignal !== 'undefined' && sig instanceof AbortSignal) {
|
|
111
|
+
return sig
|
|
112
|
+
}
|
|
113
|
+
if (
|
|
114
|
+
sig &&
|
|
115
|
+
sig.signal &&
|
|
116
|
+
typeof AbortSignal !== 'undefined' &&
|
|
117
|
+
sig.signal instanceof AbortSignal
|
|
118
|
+
) {
|
|
119
|
+
return sig.signal
|
|
120
|
+
}
|
|
121
|
+
if (sig && typeof sig === 'object' && sig.current) {
|
|
122
|
+
return resolveAbortSignal(sig.current)
|
|
123
|
+
}
|
|
124
|
+
return undefined
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export const webApi = {
|
|
128
|
+
// 1. Health & Config
|
|
129
|
+
getHealth: async () => {
|
|
130
|
+
const res = await fetch(`${API_BASE}/api/health`)
|
|
131
|
+
return await res.json()
|
|
132
|
+
},
|
|
133
|
+
|
|
134
|
+
getConfig: async () => {
|
|
135
|
+
const res = await fetch(`${API_BASE}/api/config`)
|
|
136
|
+
const json = await res.json()
|
|
137
|
+
return json.data
|
|
138
|
+
},
|
|
139
|
+
|
|
140
|
+
syncConfig: async (config) => {
|
|
141
|
+
const res = await fetch(`${API_BASE}/api/config`, {
|
|
142
|
+
method: 'POST',
|
|
143
|
+
headers: { 'Content-Type': 'application/json' },
|
|
144
|
+
body: JSON.stringify(config)
|
|
145
|
+
})
|
|
146
|
+
const json = await res.json()
|
|
147
|
+
return json.data
|
|
148
|
+
},
|
|
149
|
+
|
|
150
|
+
// 2. Chat & AI
|
|
151
|
+
fetchAI: async (params, signal = null) => {
|
|
152
|
+
const endpoint = params?.stream ? `${API_BASE}/api/ai/stream` : `${API_BASE}/api/ai/fetch`
|
|
153
|
+
const effectiveSignal = resolveAbortSignal(signal) || resolveAbortSignal(params?.signal)
|
|
154
|
+
const res = await fetch(endpoint, {
|
|
155
|
+
method: 'POST',
|
|
156
|
+
headers: { 'Content-Type': 'application/json' },
|
|
157
|
+
body: JSON.stringify(params),
|
|
158
|
+
signal: effectiveSignal
|
|
159
|
+
})
|
|
160
|
+
const json = await res.json()
|
|
161
|
+
if (!res.ok || json.error) {
|
|
162
|
+
const err = new Error(json.error?.message || `HTTP error ${res.status}`)
|
|
163
|
+
err.code = json.error?.code
|
|
164
|
+
throw err
|
|
165
|
+
}
|
|
166
|
+
return json
|
|
167
|
+
},
|
|
168
|
+
|
|
169
|
+
resetAiSession: async () => {
|
|
170
|
+
try {
|
|
171
|
+
const res = await fetch(`${API_BASE}/api/ai/reset-session`, { method: 'POST' })
|
|
172
|
+
return await res.json()
|
|
173
|
+
} catch {
|
|
174
|
+
return { success: false }
|
|
175
|
+
}
|
|
176
|
+
},
|
|
177
|
+
|
|
178
|
+
onAiToken: (callback) => {
|
|
179
|
+
addWebListener('ai:token', callback)
|
|
180
|
+
return () => removeWebListener('ai:token', callback)
|
|
181
|
+
},
|
|
182
|
+
|
|
183
|
+
onAiMood: (callback) => {
|
|
184
|
+
addWebListener('ai:mood', callback)
|
|
185
|
+
return () => removeWebListener('ai:mood', callback)
|
|
186
|
+
},
|
|
187
|
+
|
|
188
|
+
onAiMarkMeta: (callback) => {
|
|
189
|
+
addWebListener('ai:mark_meta', callback)
|
|
190
|
+
return () => removeWebListener('ai:mark_meta', callback)
|
|
191
|
+
},
|
|
192
|
+
|
|
193
|
+
onToolStatus: (callback) => {
|
|
194
|
+
addWebListener('tool:status', callback)
|
|
195
|
+
return () => removeWebListener('tool:status', callback)
|
|
196
|
+
},
|
|
197
|
+
|
|
198
|
+
abortFetchAI: () => {
|
|
199
|
+
const socket = getWebSocket()
|
|
200
|
+
if (socket && socket.readyState === WebSocket.OPEN) {
|
|
201
|
+
socket.send(JSON.stringify({ event: 'ai:abort' }))
|
|
202
|
+
}
|
|
203
|
+
fetch(`${API_BASE}/api/ai/abort`, { method: 'POST' }).catch(() => {})
|
|
204
|
+
},
|
|
205
|
+
|
|
206
|
+
onAiStatus: (callback) => {
|
|
207
|
+
addWebListener('ai:status', callback)
|
|
208
|
+
return () => removeWebListener('ai:status', callback)
|
|
209
|
+
},
|
|
210
|
+
|
|
211
|
+
onAiAbort: (callback) => {
|
|
212
|
+
addWebListener('ai:abort', callback)
|
|
213
|
+
return () => removeWebListener('ai:abort', callback)
|
|
214
|
+
},
|
|
215
|
+
|
|
216
|
+
// 3. Audio & Voice (Default imut seperti robot kecil: rate +10%, pitch +55Hz)
|
|
217
|
+
textToSpeech: async (text, rate = 10, pitch = 55, voice = 'id-ID-ArdiNeural') => {
|
|
218
|
+
// Normalisasi jika pemanggil mempassing (text, voice) atau (text, rate, pitch, voice)
|
|
219
|
+
let finalVoice = 'id-ID-ArdiNeural'
|
|
220
|
+
let finalRate = 10
|
|
221
|
+
let finalPitch = 55
|
|
222
|
+
|
|
223
|
+
if (typeof rate === 'string' && !/^-?\d+$/.test(rate.trim())) {
|
|
224
|
+
finalVoice = rate
|
|
225
|
+
} else {
|
|
226
|
+
finalRate = rate !== undefined && rate !== null && rate !== 0 ? rate : 10
|
|
227
|
+
finalPitch = pitch !== undefined && pitch !== null && pitch !== 0 ? pitch : 55
|
|
228
|
+
if (typeof voice === 'string' && voice.trim()) {
|
|
229
|
+
finalVoice = voice
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// Gunakan direct streaming endpoint untuk latensi instan tanpa base64 overhead
|
|
234
|
+
try {
|
|
235
|
+
const url = `${API_BASE}/api/tts/stream?text=${encodeURIComponent(text)}&voice=${encodeURIComponent(finalVoice)}&rate=${encodeURIComponent(finalRate)}&pitch=${encodeURIComponent(finalPitch)}`
|
|
236
|
+
return url
|
|
237
|
+
} catch (err) {
|
|
238
|
+
console.error('[webBridge] textToSpeech stream URL error:', err)
|
|
239
|
+
return null
|
|
240
|
+
}
|
|
241
|
+
},
|
|
242
|
+
|
|
243
|
+
onAudioPlay: (callback) => {
|
|
244
|
+
addWebListener('audio:play', callback)
|
|
245
|
+
},
|
|
246
|
+
|
|
247
|
+
// 4. Memory API
|
|
248
|
+
getMemories: async () => {
|
|
249
|
+
const res = await fetch(`${API_BASE}/api/memories`)
|
|
250
|
+
const json = await res.json()
|
|
251
|
+
return json.data || []
|
|
252
|
+
},
|
|
253
|
+
|
|
254
|
+
saveMemory: async (item) => {
|
|
255
|
+
const res = await fetch(`${API_BASE}/api/memories`, {
|
|
256
|
+
method: 'POST',
|
|
257
|
+
headers: { 'Content-Type': 'application/json' },
|
|
258
|
+
body: JSON.stringify(item)
|
|
259
|
+
})
|
|
260
|
+
const json = await res.json()
|
|
261
|
+
return json.data
|
|
262
|
+
},
|
|
263
|
+
|
|
264
|
+
getTurns: async () => {
|
|
265
|
+
const res = await fetch(`${API_BASE}/api/turns`)
|
|
266
|
+
const json = await res.json()
|
|
267
|
+
return json.data || []
|
|
268
|
+
},
|
|
269
|
+
|
|
270
|
+
onDatabaseRestored: (callback) => {
|
|
271
|
+
addWebListener('db:restored', callback)
|
|
272
|
+
return () => removeWebListener('db:restored', callback)
|
|
273
|
+
},
|
|
274
|
+
|
|
275
|
+
// 5. System Notifications & Windows
|
|
276
|
+
showNotification: (title, body) => {
|
|
277
|
+
// Kirim ke backend Node.js untuk Native Windows Toast Notification (tanpa web permission prompt)
|
|
278
|
+
fetch(`${API_BASE}/api/system/notify`, {
|
|
279
|
+
method: 'POST',
|
|
280
|
+
headers: { 'Content-Type': 'application/json' },
|
|
281
|
+
body: JSON.stringify({ title, body })
|
|
282
|
+
}).catch(() => {
|
|
283
|
+
// Fallback lokal ke browser Notification jika server belum siap
|
|
284
|
+
if (typeof Notification !== 'undefined' && Notification.permission === 'granted') {
|
|
285
|
+
new Notification(title, { body })
|
|
286
|
+
}
|
|
287
|
+
})
|
|
288
|
+
},
|
|
289
|
+
|
|
290
|
+
openExternal: (url) => {
|
|
291
|
+
if (typeof window !== 'undefined') {
|
|
292
|
+
window.open(url, '_blank')
|
|
293
|
+
}
|
|
294
|
+
},
|
|
295
|
+
|
|
296
|
+
// 6. Tools Execution
|
|
297
|
+
executeNativeTool: async (tool, query, config) => {
|
|
298
|
+
try {
|
|
299
|
+
const res = await fetch(`${API_BASE}/api/tools/execute`, {
|
|
300
|
+
method: 'POST',
|
|
301
|
+
headers: { 'Content-Type': 'application/json' },
|
|
302
|
+
body: JSON.stringify({ tool, query, config })
|
|
303
|
+
})
|
|
304
|
+
const json = await res.json()
|
|
305
|
+
return json
|
|
306
|
+
} catch (err) {
|
|
307
|
+
return { success: false, error: err.message }
|
|
308
|
+
}
|
|
309
|
+
},
|
|
310
|
+
|
|
311
|
+
_groupToolsCache: null,
|
|
312
|
+
getGroupTools: async () => {
|
|
313
|
+
if (webApi._groupToolsCache) return webApi._groupToolsCache
|
|
314
|
+
try {
|
|
315
|
+
const res = await fetch(`${API_BASE}/api/tools/groups`)
|
|
316
|
+
const json = await res.json()
|
|
317
|
+
if (json && json.success && json.data) {
|
|
318
|
+
webApi._groupToolsCache = json.data
|
|
319
|
+
return webApi._groupToolsCache
|
|
320
|
+
}
|
|
321
|
+
} catch (err) {
|
|
322
|
+
console.error('Gagal memuat skema group tools dari server:', err)
|
|
323
|
+
}
|
|
324
|
+
return { schema: {}, names: [], definition: {}, flat: {} }
|
|
325
|
+
},
|
|
326
|
+
|
|
327
|
+
getWorkspaceFiles: async (query = '', root = '') => {
|
|
328
|
+
try {
|
|
329
|
+
const q = encodeURIComponent(query || '')
|
|
330
|
+
const r = encodeURIComponent(root || '')
|
|
331
|
+
const res = await fetch(`${API_BASE}/api/workspace/files?query=${q}&root=${r}`)
|
|
332
|
+
const json = await res.json()
|
|
333
|
+
return json?.data || []
|
|
334
|
+
} catch (err) {
|
|
335
|
+
console.error('[webBridge] getWorkspaceFiles error:', err)
|
|
336
|
+
return []
|
|
337
|
+
}
|
|
338
|
+
},
|
|
339
|
+
|
|
340
|
+
checkToolApproval: async (tool, query) => {
|
|
341
|
+
try {
|
|
342
|
+
const res = await fetch(`${API_BASE}/api/tools/needs-approval`, {
|
|
343
|
+
method: 'POST',
|
|
344
|
+
headers: { 'Content-Type': 'application/json' },
|
|
345
|
+
body: JSON.stringify({ tool, query })
|
|
346
|
+
})
|
|
347
|
+
return await res.json()
|
|
348
|
+
} catch (_) {
|
|
349
|
+
return { needsApproval: false }
|
|
350
|
+
}
|
|
351
|
+
},
|
|
352
|
+
|
|
353
|
+
needsApproval: async (tool, query) => {
|
|
354
|
+
return webApi.checkToolApproval(tool, query)
|
|
355
|
+
},
|
|
356
|
+
|
|
357
|
+
selectDirectory: async (description = 'Pilih Folder Workspace Proyek') => {
|
|
358
|
+
try {
|
|
359
|
+
const res = await webApi.executeNativeTool('select-directory', description)
|
|
360
|
+
if (res && res.success && res.path) {
|
|
361
|
+
return res.path
|
|
362
|
+
}
|
|
363
|
+
return null
|
|
364
|
+
} catch (_) {
|
|
365
|
+
return null
|
|
366
|
+
}
|
|
367
|
+
},
|
|
368
|
+
|
|
369
|
+
// Browser Automation Bridges
|
|
370
|
+
browserNavigate: async (url) => webApi.executeNativeTool('browser-navigate', url),
|
|
371
|
+
browserReadDom: async () => webApi.executeNativeTool('browser-read-dom', ''),
|
|
372
|
+
browserAction: async (data) =>
|
|
373
|
+
webApi.executeNativeTool(
|
|
374
|
+
'browser-action',
|
|
375
|
+
typeof data === 'string' ? data : JSON.stringify(data)
|
|
376
|
+
),
|
|
377
|
+
browserClose: async (sessionId = 'default') =>
|
|
378
|
+
webApi.executeNativeTool(
|
|
379
|
+
'browser-close',
|
|
380
|
+
typeof sessionId === 'string' ? sessionId : sessionId?.sessionId || 'default'
|
|
381
|
+
),
|
|
382
|
+
showBrowserWindow: async (sessionId = 'default') =>
|
|
383
|
+
webApi.executeNativeTool('browser-show', typeof sessionId === 'string' ? sessionId : 'default'),
|
|
384
|
+
hideBrowserWindow: async (sessionId = 'default') =>
|
|
385
|
+
webApi.executeNativeTool('browser-hide', typeof sessionId === 'string' ? sessionId : 'default'),
|
|
386
|
+
onBrowserPreview: (cb) => {
|
|
387
|
+
addWebListener('browser:preview', cb)
|
|
388
|
+
},
|
|
389
|
+
|
|
390
|
+
// Windows Desktop OS Tools Bridges
|
|
391
|
+
osRead: async () => webApi.executeNativeTool('os-read', ''),
|
|
392
|
+
osClick: async (query) => webApi.executeNativeTool('os-click', query),
|
|
393
|
+
osType: async (query) => webApi.executeNativeTool('os-type', query),
|
|
394
|
+
osKey: async (combo) => webApi.executeNativeTool('os-key', combo),
|
|
395
|
+
osScroll: async (query) => webApi.executeNativeTool('os-scroll', query),
|
|
396
|
+
osOpen: async (target) => webApi.executeNativeTool('os-open', target),
|
|
397
|
+
osListWindows: async () => webApi.executeNativeTool('os-list-windows', ''),
|
|
398
|
+
osFocusWindow: async (title) => webApi.executeNativeTool('os-focus-window', title),
|
|
399
|
+
|
|
400
|
+
// 7. Pure Node.js Skills Engine
|
|
401
|
+
getSkills: async () => {
|
|
402
|
+
try {
|
|
403
|
+
const res = await fetch(`${API_BASE}/api/skills`)
|
|
404
|
+
const json = await res.json()
|
|
405
|
+
return json.data || []
|
|
406
|
+
} catch (_) {
|
|
407
|
+
return []
|
|
408
|
+
}
|
|
409
|
+
},
|
|
410
|
+
|
|
411
|
+
getSkillTree: async (name) => {
|
|
412
|
+
try {
|
|
413
|
+
const res = await fetch(`${API_BASE}/api/skills/${encodeURIComponent(name)}/tree`)
|
|
414
|
+
const json = await res.json()
|
|
415
|
+
return json.data || []
|
|
416
|
+
} catch (_) {
|
|
417
|
+
return []
|
|
418
|
+
}
|
|
419
|
+
},
|
|
420
|
+
|
|
421
|
+
readSkillFile: async (name, filePath = 'SKILL.md') => {
|
|
422
|
+
try {
|
|
423
|
+
const res = await fetch(
|
|
424
|
+
`${API_BASE}/api/skills/${encodeURIComponent(name)}/file?filePath=${encodeURIComponent(filePath)}`
|
|
425
|
+
)
|
|
426
|
+
const json = await res.json()
|
|
427
|
+
return json.data?.content || ''
|
|
428
|
+
} catch (_) {
|
|
429
|
+
return ''
|
|
430
|
+
}
|
|
431
|
+
},
|
|
432
|
+
|
|
433
|
+
readSkill: async (name) => {
|
|
434
|
+
const fileRes = await webApi.readSkillFile(name, 'SKILL.md')
|
|
435
|
+
if (fileRes) return fileRes
|
|
436
|
+
try {
|
|
437
|
+
const serverRes = await webApi.executeNativeTool('read-skill', { skill_name: name })
|
|
438
|
+
if (serverRes && serverRes.success && (serverRes.content || serverRes.data)) {
|
|
439
|
+
return serverRes.content || serverRes.data
|
|
440
|
+
}
|
|
441
|
+
} catch {
|
|
442
|
+
// ignore fallback error
|
|
443
|
+
}
|
|
444
|
+
return ''
|
|
445
|
+
},
|
|
446
|
+
|
|
447
|
+
saveSkillFile: async (name, filePath, content) => {
|
|
448
|
+
const res = await fetch(`${API_BASE}/api/skills/${encodeURIComponent(name)}/file`, {
|
|
449
|
+
method: 'POST',
|
|
450
|
+
headers: { 'Content-Type': 'application/json' },
|
|
451
|
+
body: JSON.stringify({ filePath, content })
|
|
452
|
+
})
|
|
453
|
+
return await res.json()
|
|
454
|
+
},
|
|
455
|
+
|
|
456
|
+
saveSkill: async (name, content) => {
|
|
457
|
+
return await webApi.saveSkillFile(name, 'SKILL.md', content)
|
|
458
|
+
},
|
|
459
|
+
|
|
460
|
+
createSkillItem: async (name, itemPath, isFolder = false) => {
|
|
461
|
+
const res = await fetch(`${API_BASE}/api/skills/${encodeURIComponent(name)}/item`, {
|
|
462
|
+
method: 'POST',
|
|
463
|
+
headers: { 'Content-Type': 'application/json' },
|
|
464
|
+
body: JSON.stringify({ itemPath, isFolder })
|
|
465
|
+
})
|
|
466
|
+
return await res.json()
|
|
467
|
+
},
|
|
468
|
+
|
|
469
|
+
renameSkillItem: async (name, oldPath, newPath) => {
|
|
470
|
+
const res = await fetch(`${API_BASE}/api/skills/${encodeURIComponent(name)}/rename`, {
|
|
471
|
+
method: 'POST',
|
|
472
|
+
headers: { 'Content-Type': 'application/json' },
|
|
473
|
+
body: JSON.stringify({ oldPath, newPath })
|
|
474
|
+
})
|
|
475
|
+
return await res.json()
|
|
476
|
+
},
|
|
477
|
+
|
|
478
|
+
deleteSkillItem: async (name, itemPath) => {
|
|
479
|
+
const res = await fetch(`${API_BASE}/api/skills/${encodeURIComponent(name)}/item`, {
|
|
480
|
+
method: 'DELETE',
|
|
481
|
+
headers: { 'Content-Type': 'application/json' },
|
|
482
|
+
body: JSON.stringify({ itemPath })
|
|
483
|
+
})
|
|
484
|
+
return await res.json()
|
|
485
|
+
},
|
|
486
|
+
|
|
487
|
+
deleteSkill: async (name) => {
|
|
488
|
+
const res = await fetch(`${API_BASE}/api/skills/${encodeURIComponent(name)}`, {
|
|
489
|
+
method: 'DELETE'
|
|
490
|
+
})
|
|
491
|
+
return await res.json()
|
|
492
|
+
},
|
|
493
|
+
|
|
494
|
+
installSkill: async (fileOrBuffer, overrideName = null) => {
|
|
495
|
+
const body =
|
|
496
|
+
fileOrBuffer instanceof File || fileOrBuffer instanceof Blob
|
|
497
|
+
? fileOrBuffer
|
|
498
|
+
: new Blob([fileOrBuffer])
|
|
499
|
+
const url = overrideName
|
|
500
|
+
? `${API_BASE}/api/skills/install?name=${encodeURIComponent(overrideName)}`
|
|
501
|
+
: `${API_BASE}/api/skills/install`
|
|
502
|
+
const res = await fetch(url, {
|
|
503
|
+
method: 'POST',
|
|
504
|
+
headers: { 'Content-Type': 'application/zip' },
|
|
505
|
+
body
|
|
506
|
+
})
|
|
507
|
+
return await res.json()
|
|
508
|
+
},
|
|
509
|
+
|
|
510
|
+
onSkillsUpdated: (cb) => {
|
|
511
|
+
addWebListener('skills:updated', cb)
|
|
512
|
+
return () => removeWebListener('skills:updated', cb)
|
|
513
|
+
},
|
|
514
|
+
|
|
515
|
+
// 8. Dynamic Plugins Engine
|
|
516
|
+
getPlugins: async () => {
|
|
517
|
+
try {
|
|
518
|
+
const res = await fetch(`${API_BASE}/api/plugins`)
|
|
519
|
+
const json = await res.json()
|
|
520
|
+
return json.data || []
|
|
521
|
+
} catch (_) {
|
|
522
|
+
return []
|
|
523
|
+
}
|
|
524
|
+
},
|
|
525
|
+
|
|
526
|
+
reloadPlugins: async () => {
|
|
527
|
+
const res = await fetch(`${API_BASE}/api/plugins/reload`, { method: 'POST' })
|
|
528
|
+
const json = await res.json()
|
|
529
|
+
return json.data || []
|
|
530
|
+
},
|
|
531
|
+
|
|
532
|
+
createPlugin: async (payload) => {
|
|
533
|
+
const res = await fetch(`${API_BASE}/api/plugins/save`, {
|
|
534
|
+
method: 'POST',
|
|
535
|
+
headers: { 'Content-Type': 'application/json' },
|
|
536
|
+
body: JSON.stringify(payload)
|
|
537
|
+
})
|
|
538
|
+
return await res.json()
|
|
539
|
+
},
|
|
540
|
+
|
|
541
|
+
togglePlugin: async (name, isEnabled) => {
|
|
542
|
+
const res = await fetch(`${API_BASE}/api/plugins/toggle`, {
|
|
543
|
+
method: 'POST',
|
|
544
|
+
headers: { 'Content-Type': 'application/json' },
|
|
545
|
+
body: JSON.stringify({ name, isEnabled })
|
|
546
|
+
})
|
|
547
|
+
return await res.json()
|
|
548
|
+
},
|
|
549
|
+
|
|
550
|
+
deletePlugin: async (name) => {
|
|
551
|
+
const res = await fetch(`${API_BASE}/api/plugins/${encodeURIComponent(name)}`, {
|
|
552
|
+
method: 'DELETE'
|
|
553
|
+
})
|
|
554
|
+
return await res.json()
|
|
555
|
+
},
|
|
556
|
+
|
|
557
|
+
executePluginAction: async (action, query) => {
|
|
558
|
+
const res = await fetch(`${API_BASE}/api/plugins/execute`, {
|
|
559
|
+
method: 'POST',
|
|
560
|
+
headers: { 'Content-Type': 'application/json' },
|
|
561
|
+
body: JSON.stringify({ action, query })
|
|
562
|
+
})
|
|
563
|
+
return await res.json()
|
|
564
|
+
},
|
|
565
|
+
|
|
566
|
+
executePlugin: async (action, query) => {
|
|
567
|
+
return webApi.executePluginAction(action, query)
|
|
568
|
+
},
|
|
569
|
+
|
|
570
|
+
openPluginFolder: async () => {
|
|
571
|
+
return webApi.executeNativeTool(
|
|
572
|
+
'run-powershell',
|
|
573
|
+
'explorer.exe "$HOME\\Documents\\Mark Plugins"'
|
|
574
|
+
)
|
|
575
|
+
},
|
|
576
|
+
|
|
577
|
+
openSpecificFolder: async (folderPath) => {
|
|
578
|
+
return webApi.executeNativeTool('run-powershell', `explorer.exe "${folderPath}"`)
|
|
579
|
+
},
|
|
580
|
+
|
|
581
|
+
onPluginsUpdated: (cb) => {
|
|
582
|
+
addWebListener('plugins:updated', cb)
|
|
583
|
+
return () => removeWebListener('plugins:updated', cb)
|
|
584
|
+
},
|
|
585
|
+
|
|
586
|
+
// 9. Document RAG Binary Parser
|
|
587
|
+
parseDocument: async (arrayBuffer, isDocx = false) => {
|
|
588
|
+
const res = await fetch(`${API_BASE}/api/documents/parse?isDocx=${isDocx}`, {
|
|
589
|
+
method: 'POST',
|
|
590
|
+
headers: { 'Content-Type': 'application/octet-stream' },
|
|
591
|
+
body: arrayBuffer
|
|
592
|
+
})
|
|
593
|
+
const json = await res.json()
|
|
594
|
+
if (!res.ok || !json.success) throw new Error(json.error || 'Parse error')
|
|
595
|
+
return json.text
|
|
596
|
+
},
|
|
597
|
+
|
|
598
|
+
// 10. Awareness & OS Vision
|
|
599
|
+
getActivityBuffer: async () => {
|
|
600
|
+
try {
|
|
601
|
+
const res = await fetch(`${API_BASE}/api/awareness/activity-buffer`)
|
|
602
|
+
const json = await res.json()
|
|
603
|
+
const list = Array.isArray(json.data) ? [...json.data] : []
|
|
604
|
+
if (json.telemetry) {
|
|
605
|
+
list.telemetry = json.telemetry
|
|
606
|
+
}
|
|
607
|
+
return list
|
|
608
|
+
} catch (_) {
|
|
609
|
+
return []
|
|
610
|
+
}
|
|
611
|
+
},
|
|
612
|
+
|
|
613
|
+
getSystemTelemetry: async () => {
|
|
614
|
+
try {
|
|
615
|
+
const res = await fetch(`${API_BASE}/api/awareness/telemetry`)
|
|
616
|
+
const json = await res.json()
|
|
617
|
+
return json.telemetry || null
|
|
618
|
+
} catch (_) {
|
|
619
|
+
return null
|
|
620
|
+
}
|
|
621
|
+
},
|
|
622
|
+
|
|
623
|
+
clearActivityBuffer: async () => {
|
|
624
|
+
try {
|
|
625
|
+
const res = await fetch(`${API_BASE}/api/awareness/clear-buffer`, { method: 'POST' })
|
|
626
|
+
return await res.json()
|
|
627
|
+
} catch (_) {
|
|
628
|
+
return { success: false }
|
|
629
|
+
}
|
|
630
|
+
},
|
|
631
|
+
|
|
632
|
+
getSystemIdleSeconds: async () => {
|
|
633
|
+
try {
|
|
634
|
+
const res = await fetch(`${API_BASE}/api/awareness/idle-time`)
|
|
635
|
+
const json = await res.json()
|
|
636
|
+
return json.idleSeconds || 0
|
|
637
|
+
} catch (_) {
|
|
638
|
+
return 0
|
|
639
|
+
}
|
|
640
|
+
},
|
|
641
|
+
|
|
642
|
+
takeScreenshot: async () => {
|
|
643
|
+
const res = await fetch(`${API_BASE}/api/os/screenshot`, { method: 'POST' })
|
|
644
|
+
const json = await res.json()
|
|
645
|
+
if (!json.success) throw new Error(json.error || 'Failed to capture screenshot')
|
|
646
|
+
return json.data
|
|
647
|
+
},
|
|
648
|
+
|
|
649
|
+
// 11. Google Workspace API
|
|
650
|
+
googleStatus: async () => {
|
|
651
|
+
try {
|
|
652
|
+
const res = await fetch(`${API_BASE}/api/google/status`)
|
|
653
|
+
const json = await res.json()
|
|
654
|
+
return json
|
|
655
|
+
} catch (_) {
|
|
656
|
+
return { success: false, isConnected: false }
|
|
657
|
+
}
|
|
658
|
+
},
|
|
659
|
+
googleConnect: async (clientId, clientSecret) => {
|
|
660
|
+
const res = await fetch(`${API_BASE}/api/google/connect`, {
|
|
661
|
+
method: 'POST',
|
|
662
|
+
headers: { 'Content-Type': 'application/json' },
|
|
663
|
+
body: JSON.stringify({ clientId, clientSecret })
|
|
664
|
+
})
|
|
665
|
+
return await res.json()
|
|
666
|
+
},
|
|
667
|
+
googleDisconnect: async () => {
|
|
668
|
+
const res = await fetch(`${API_BASE}/api/google/disconnect`, { method: 'POST' })
|
|
669
|
+
return await res.json()
|
|
670
|
+
},
|
|
671
|
+
|
|
672
|
+
// 12. Telegram Bot API & Listeners
|
|
673
|
+
tgGetStatus: async () => {
|
|
674
|
+
try {
|
|
675
|
+
const res = await fetch(`${API_BASE}/api/telegram/status`)
|
|
676
|
+
return await res.json()
|
|
677
|
+
} catch (_) {
|
|
678
|
+
return { status: 'disconnected' }
|
|
679
|
+
}
|
|
680
|
+
},
|
|
681
|
+
tgGetHistory: async () => {
|
|
682
|
+
try {
|
|
683
|
+
const res = await fetch(`${API_BASE}/api/telegram/history`)
|
|
684
|
+
const json = await res.json()
|
|
685
|
+
return json.data || []
|
|
686
|
+
} catch (_) {
|
|
687
|
+
return []
|
|
688
|
+
}
|
|
689
|
+
},
|
|
690
|
+
tgStart: async (token) => {
|
|
691
|
+
const res = await fetch(`${API_BASE}/api/telegram/start`, {
|
|
692
|
+
method: 'POST',
|
|
693
|
+
headers: { 'Content-Type': 'application/json' },
|
|
694
|
+
body: JSON.stringify({ token })
|
|
695
|
+
})
|
|
696
|
+
return await res.json()
|
|
697
|
+
},
|
|
698
|
+
tgStop: async () => {
|
|
699
|
+
const res = await fetch(`${API_BASE}/api/telegram/stop`, { method: 'POST' })
|
|
700
|
+
return await res.json()
|
|
701
|
+
},
|
|
702
|
+
tgSendMessage: async (chatId, message) => {
|
|
703
|
+
const res = await fetch(`${API_BASE}/api/telegram/send`, {
|
|
704
|
+
method: 'POST',
|
|
705
|
+
headers: { 'Content-Type': 'application/json' },
|
|
706
|
+
body: JSON.stringify({ chatId, message })
|
|
707
|
+
})
|
|
708
|
+
return await res.json()
|
|
709
|
+
},
|
|
710
|
+
tgAgentExecutionDone: async (payload) => {
|
|
711
|
+
const res = await fetch(`${API_BASE}/api/telegram/agent-done`, {
|
|
712
|
+
method: 'POST',
|
|
713
|
+
headers: { 'Content-Type': 'application/json' },
|
|
714
|
+
body: JSON.stringify(payload)
|
|
715
|
+
})
|
|
716
|
+
return await res.json()
|
|
717
|
+
},
|
|
718
|
+
sendTgAgentExecutionDone: async (payload) => {
|
|
719
|
+
return await webApi.tgAgentExecutionDone(payload)
|
|
720
|
+
},
|
|
721
|
+
tgBroadcastToAdmins: async (message) => {
|
|
722
|
+
const res = await fetch(`${API_BASE}/api/telegram/broadcast`, {
|
|
723
|
+
method: 'POST',
|
|
724
|
+
headers: { 'Content-Type': 'application/json' },
|
|
725
|
+
body: JSON.stringify({ message })
|
|
726
|
+
})
|
|
727
|
+
return await res.json()
|
|
728
|
+
},
|
|
729
|
+
tgTakeScreenshot: async (chatId = null) => {
|
|
730
|
+
const res = await fetch(`${API_BASE}/api/telegram/screenshot`, {
|
|
731
|
+
method: 'POST',
|
|
732
|
+
headers: { 'Content-Type': 'application/json' },
|
|
733
|
+
body: JSON.stringify({ chatId })
|
|
734
|
+
})
|
|
735
|
+
return await res.json()
|
|
736
|
+
},
|
|
737
|
+
onTgCommandAccept: (cb) => {
|
|
738
|
+
addWebListener('tg:command-accept', cb)
|
|
739
|
+
return () => removeWebListener('tg:command-accept', cb)
|
|
740
|
+
},
|
|
741
|
+
onTgCommandAlways: (cb) => {
|
|
742
|
+
addWebListener('tg:command-always', cb)
|
|
743
|
+
return () => removeWebListener('tg:command-always', cb)
|
|
744
|
+
},
|
|
745
|
+
onTgCommandReject: (cb) => {
|
|
746
|
+
addWebListener('tg:command-reject', cb)
|
|
747
|
+
return () => removeWebListener('tg:command-reject', cb)
|
|
748
|
+
},
|
|
749
|
+
onTgCommandSession: (cb) => {
|
|
750
|
+
addWebListener('tg:command-session', cb)
|
|
751
|
+
return () => removeWebListener('tg:command-session', cb)
|
|
752
|
+
},
|
|
753
|
+
onTgConnection: (cb) => {
|
|
754
|
+
addWebListener('tg:connection', cb)
|
|
755
|
+
return () => removeWebListener('tg:connection', cb)
|
|
756
|
+
},
|
|
757
|
+
onTgThinking: (cb) => {
|
|
758
|
+
addWebListener('tg:thinking', cb)
|
|
759
|
+
return () => removeWebListener('tg:thinking', cb)
|
|
760
|
+
},
|
|
761
|
+
onTgMessage: (cb) => {
|
|
762
|
+
addWebListener('tg:message', cb)
|
|
763
|
+
return () => removeWebListener('tg:message', cb)
|
|
764
|
+
},
|
|
765
|
+
onTgReplySent: (cb) => {
|
|
766
|
+
addWebListener('tg:reply-sent', cb)
|
|
767
|
+
return () => removeWebListener('tg:reply-sent', cb)
|
|
768
|
+
},
|
|
769
|
+
onTgRequestAgentExecution: (cb) => {
|
|
770
|
+
addWebListener('tg:request-agent-execution', cb)
|
|
771
|
+
return () => removeWebListener('tg:request-agent-execution', cb)
|
|
772
|
+
},
|
|
773
|
+
|
|
774
|
+
// 13. Background Task Daemon API
|
|
775
|
+
spawnBackgroundTask: async (taskId, command, cwd) => {
|
|
776
|
+
const res = await fetch(`${API_BASE}/api/tasks/daemon/spawn`, {
|
|
777
|
+
method: 'POST',
|
|
778
|
+
headers: { 'Content-Type': 'application/json' },
|
|
779
|
+
body: JSON.stringify({ taskId, command, cwd })
|
|
780
|
+
})
|
|
781
|
+
return await res.json()
|
|
782
|
+
},
|
|
783
|
+
readBackgroundTaskOutput: async (taskId, lines = 40) => {
|
|
784
|
+
const res = await fetch(
|
|
785
|
+
`${API_BASE}/api/tasks/daemon/${encodeURIComponent(taskId)}/output?lines=${lines}`
|
|
786
|
+
)
|
|
787
|
+
return await res.json()
|
|
788
|
+
},
|
|
789
|
+
killBackgroundTask: async (taskId) => {
|
|
790
|
+
const res = await fetch(`${API_BASE}/api/tasks/daemon/${encodeURIComponent(taskId)}/kill`, {
|
|
791
|
+
method: 'POST'
|
|
792
|
+
})
|
|
793
|
+
return await res.json()
|
|
794
|
+
},
|
|
795
|
+
listBackgroundTasks: async () => {
|
|
796
|
+
const res = await fetch(`${API_BASE}/api/tasks/daemon/list`)
|
|
797
|
+
return await res.json()
|
|
798
|
+
},
|
|
799
|
+
|
|
800
|
+
// 14. Database Backup & Restore API
|
|
801
|
+
exportDatabase: async () => {
|
|
802
|
+
const res = await fetch(`${API_BASE}/api/db/export`)
|
|
803
|
+
const json = await res.json()
|
|
804
|
+
return json.data || json
|
|
805
|
+
},
|
|
806
|
+
restoreDatabase: async (dumpData, overwrite = true) => {
|
|
807
|
+
const res = await fetch(`${API_BASE}/api/db/restore`, {
|
|
808
|
+
method: 'POST',
|
|
809
|
+
headers: { 'Content-Type': 'application/json' },
|
|
810
|
+
body: JSON.stringify({ dumpData, overwrite })
|
|
811
|
+
})
|
|
812
|
+
const json = await res.json()
|
|
813
|
+
if (!res.ok || !json.success) {
|
|
814
|
+
throw new Error(json.error || 'Gagal memulihkan database.')
|
|
815
|
+
}
|
|
816
|
+
return json
|
|
817
|
+
},
|
|
818
|
+
saveTempFile: async (dataUrlOrBuffer, fileName = 'file.png') => {
|
|
819
|
+
try {
|
|
820
|
+
let dataUrl = typeof dataUrlOrBuffer === 'string' ? dataUrlOrBuffer : null
|
|
821
|
+
if (!dataUrl && dataUrlOrBuffer instanceof ArrayBuffer) {
|
|
822
|
+
const bytes = new Uint8Array(dataUrlOrBuffer)
|
|
823
|
+
let binary = ''
|
|
824
|
+
for (let i = 0; i < bytes.byteLength; i++) {
|
|
825
|
+
binary += String.fromCharCode(bytes[i])
|
|
826
|
+
}
|
|
827
|
+
dataUrl = `data:application/octet-stream;base64,${btoa(binary)}`
|
|
828
|
+
}
|
|
829
|
+
const res = await fetch(`${API_BASE}/api/chat/upload-temp`, {
|
|
830
|
+
method: 'POST',
|
|
831
|
+
headers: { 'Content-Type': 'application/json' },
|
|
832
|
+
body: JSON.stringify({ fileName, dataUrl })
|
|
833
|
+
})
|
|
834
|
+
const json = await res.json()
|
|
835
|
+
if (json && json.success) return json.path
|
|
836
|
+
} catch (e) {
|
|
837
|
+
console.error('[webBridge] saveTempFile error:', e)
|
|
838
|
+
}
|
|
839
|
+
return null
|
|
840
|
+
},
|
|
841
|
+
|
|
842
|
+
// Window Controls (WebUI App Mode)
|
|
843
|
+
windowMinimize: () => {},
|
|
844
|
+
windowMaximize: () => {},
|
|
845
|
+
windowClose: () => {
|
|
846
|
+
if (typeof window !== 'undefined') window.close()
|
|
847
|
+
},
|
|
848
|
+
onWindowMaximized: () => {},
|
|
849
|
+
|
|
850
|
+
getYoutubeTranscript: async (url) => {
|
|
851
|
+
const res = await webApi.executeNativeTool('youtube-transcript', url)
|
|
852
|
+
return res.data || ''
|
|
853
|
+
},
|
|
854
|
+
searchYoutube: async (query) => {
|
|
855
|
+
const res = await webApi.executeNativeTool('search-youtube', query)
|
|
856
|
+
return res.data || []
|
|
857
|
+
},
|
|
858
|
+
searchMusic: async (query) => {
|
|
859
|
+
const res = await webApi.executeNativeTool('search-youtube', query)
|
|
860
|
+
return res.data || []
|
|
861
|
+
},
|
|
862
|
+
|
|
863
|
+
// 13. Inter-Agent & WebSocket Broadcast Bridge
|
|
864
|
+
broadcastWsEvent: (event, data) => {
|
|
865
|
+
if (typeof window === 'undefined') return
|
|
866
|
+
const socket = getWebSocket()
|
|
867
|
+
if (socket && socket.readyState === WebSocket.OPEN) {
|
|
868
|
+
socket.send(JSON.stringify({ event: 'ws:broadcast', payload: { event, data } }))
|
|
869
|
+
}
|
|
870
|
+
},
|
|
871
|
+
onSubagentReport: (cb) => {
|
|
872
|
+
addWebListener('subagent:report', cb)
|
|
873
|
+
return () => removeWebListener('subagent:report', cb)
|
|
874
|
+
},
|
|
875
|
+
onSubagentCompleted: (cb) => {
|
|
876
|
+
addWebListener('subagent:completed', cb)
|
|
877
|
+
return () => removeWebListener('subagent:completed', cb)
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
// Inisialisasi otomatis WebSocket saat dimuat di browser
|
|
882
|
+
if (typeof window !== 'undefined') {
|
|
883
|
+
window.api = { ...webApi, ...(window.api || {}) }
|
|
884
|
+
getWebSocket()
|
|
885
|
+
}
|