@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,413 @@
1
+ import readline from 'readline'
2
+ import http from 'http'
3
+ import { WebSocket } from 'ws'
4
+ import { colors as c, drawLeftRail, drawDivider, resolveWidth, stripAnsi } from './theme.js'
5
+ import { launchUI, closeUI } from '../server/launcher.js'
6
+ import { checkForUpdate, getCurrentVersion } from '../server/services/updater.js'
7
+
8
+ const SERVER_URL = process.env.MARK_SERVER_URL || 'http://localhost:3000'
9
+ const WS_URL = process.env.MARK_WS_URL || 'ws://localhost:3000/stream'
10
+
11
+ let activeServerPort = 3000
12
+ let isUiActive = false
13
+ let currentConfig = {}
14
+ let lastFetchPayload = null
15
+ let isJsonInspectorOpen = false
16
+ let updateInfo = null
17
+ let isUpdateModalOpen = false
18
+
19
+ export function setUpdateInfo(info) {
20
+ updateInfo = info
21
+ }
22
+
23
+ export function getUpdateInfo() {
24
+ return updateInfo
25
+ }
26
+
27
+ function getTimeString() {
28
+ return new Date().toLocaleTimeString('id-ID', {
29
+ hour: '2-digit',
30
+ minute: '2-digit',
31
+ second: '2-digit'
32
+ })
33
+ }
34
+
35
+ async function checkServerHealth() {
36
+ return new Promise((resolve) => {
37
+ http
38
+ .get(`${SERVER_URL}/api/health`, (res) => {
39
+ resolve(res.statusCode === 200)
40
+ })
41
+ .on('error', () => {
42
+ resolve(false)
43
+ })
44
+ })
45
+ }
46
+
47
+ async function fetchConfig() {
48
+ try {
49
+ const res = await fetch(`${SERVER_URL}/api/config`)
50
+ const data = await res.json()
51
+ return data.config || {}
52
+ } catch (_) {
53
+ return {}
54
+ }
55
+ }
56
+
57
+ export function printMonitorHeader(config = {}, uiActive = false) {
58
+ const provider = config.aiProvider || 'gemini-web'
59
+ const model =
60
+ provider === 'gemini-web'
61
+ ? config.geminiWebModel || 'gemini-3.6-flash'
62
+ : provider === 'custom'
63
+ ? config.customModel || 'default-model'
64
+ : config.model || 'local-model'
65
+ const cwd = process.cwd()
66
+ const termWidth = resolveWidth(null, 78)
67
+
68
+ const agentStatus = uiActive
69
+ ? `${c.green}● Aktif${c.reset} ${c.darkGray}(Siap Digunakan)${c.reset}`
70
+ : `${c.yellow}○ Standby${c.reset} ${c.darkGray}(Jendela Ditutup)${c.reset}`
71
+
72
+ const maxCwd = Math.max(15, termWidth - 18)
73
+ const displayCwd = cwd.length > maxCwd ? '...' + cwd.slice(-(maxCwd - 3)) : cwd
74
+
75
+ const serverLine =
76
+ termWidth < 68
77
+ ? ` ${c.darkGray}Core Server:${c.reset} ${c.blue}http://localhost:${activeServerPort}${c.reset}`
78
+ : ` ${c.darkGray}Core Server:${c.reset} ${c.blue}http://localhost:${activeServerPort}${c.reset} ${c.darkGray}|${c.reset} ${c.darkGray}Status:${c.reset} ${c.teal}Online${c.reset}`
79
+
80
+ const lines = [
81
+ ` ${c.bold}${c.green}● MARK${c.reset} ${c.white}Autonomous Companion${c.reset} ${c.darkGray}[v${getCurrentVersion()}]${c.reset}`,
82
+ ` ${c.darkGray}Workspace :${c.reset} ${c.gray}${displayCwd}${c.reset}`,
83
+ serverLine,
84
+ ` ${c.darkGray}Status MARK:${c.reset} ${agentStatus}`,
85
+ ` ${c.darkGray}AI Model :${c.reset} ${c.cyan}${provider}${c.reset} ${c.darkGray}(${model})${c.reset}`
86
+ ]
87
+
88
+ if (updateInfo && updateInfo.hasUpdate) {
89
+ lines.push('')
90
+ const updateTitle =
91
+ termWidth < 70
92
+ ? `▲ UPDATE: v${updateInfo.currentVersion} → v${updateInfo.latestVersion} [p]`
93
+ : `▲ UPDATE TERSEDIA: v${updateInfo.currentVersion} → v${updateInfo.latestVersion} (Tekan [p] untuk info)`
94
+ lines.push(` ${c.bold}${c.yellow}${updateTitle}${c.reset}`)
95
+ lines.push(
96
+ ` ${c.darkGray}Perintah :${c.reset} ${c.green}${updateInfo.instruction || 'npm i -g @mazees/mark'}${c.reset}`
97
+ )
98
+ }
99
+
100
+ if (!uiActive) {
101
+ lines.push('')
102
+ const standbyMsg =
103
+ termWidth < 65
104
+ ? 'MARK standby. Tekan [u] untuk buka.'
105
+ : 'MARK sedang standby. Tekan [u] untuk membuka MARK.'
106
+ lines.push(` ${c.yellow}${standbyMsg}${c.reset}`)
107
+ }
108
+
109
+ // Bersihkan layar & reset scrolling region sementara untuk render header
110
+ process.stdout.write('\x1b[r\x1b[2J\x1b[1;1H')
111
+ drawLeftRail('', lines, termWidth, uiActive ? c.darkGray : c.yellow)
112
+
113
+ let shortcutsText = ''
114
+ if (termWidth < 60) {
115
+ shortcutsText = ` ${c.darkGray}Keys:${c.reset} ${c.green}[u]${c.reset}${c.gray}UI${c.reset}${updateInfo?.hasUpdate ? ` ${c.green}[p]${c.reset}${c.yellow}Upd${c.reset}` : ''} ${c.green}[c]${c.reset}${c.gray}Clr${c.reset} ${c.green}[q]${c.reset}${c.gray}Quit${c.reset}`
116
+ } else if (termWidth < 76) {
117
+ shortcutsText = ` ${c.darkGray}Shortcuts:${c.reset} ${c.green}[u]${c.reset} ${c.gray}Buka${c.reset}${updateInfo?.hasUpdate ? ` | ${c.green}[p]${c.reset} ${c.yellow}Update${c.reset}` : ''} | ${c.green}[c]${c.reset} ${c.gray}Bersih${c.reset} | ${c.green}[q]${c.reset} ${c.gray}Keluar${c.reset}`
118
+ } else {
119
+ const updateShortcut = updateInfo?.hasUpdate
120
+ ? ` ${c.darkGray}|${c.reset} ${c.green}[p]${c.reset} ${c.yellow}Update Info${c.reset}`
121
+ : ''
122
+ shortcutsText = ` ${c.darkGray}Shortcuts:${c.reset} ${c.green}[u]${c.reset} ${c.gray}Buka MARK${c.reset}${updateShortcut} ${c.darkGray}|${c.reset} ${c.green}[c]${c.reset} ${c.gray}Bersihkan Layar${c.reset} ${c.darkGray}|${c.reset} ${c.green}[q]${c.reset} ${c.gray}Keluar${c.reset}`
123
+ }
124
+ console.log(shortcutsText + '\n')
125
+ console.log(' ' + drawDivider('Live Activity', termWidth - 1, c.darkGray))
126
+
127
+ // Kunci baris 1 s/d headerHeight agar tidak tertimbun oleh scroll log
128
+ const headerHeight = lines.length + 5
129
+ const totalRows = process.stdout.rows || 30
130
+ if (totalRows > headerHeight + 2) {
131
+ process.stdout.write(`\x1b[${headerHeight + 1};${totalRows}r`)
132
+ process.stdout.write(`\x1b[${headerHeight + 1};1H`)
133
+ }
134
+ }
135
+
136
+ export function logActivity(type, title, detail = '') {
137
+ const time = getTimeString()
138
+ let badge = `${c.darkGray}● Info ${c.reset}`
139
+ if (type === 'agent') badge = `${c.cyan}● Agent ${c.reset}`
140
+ else if (type === 'tool') badge = `${c.yellow}⚡ Tool ${c.reset}`
141
+ else if (type === 'result') badge = `${c.green}✓ Result ${c.reset}`
142
+ else if (type === 'thought') badge = `${c.purple}● Thought${c.reset}`
143
+ else if (type === 'fetch') badge = `${c.blue}📡 Fetch ${c.reset}`
144
+ else if (type === 'error') badge = `${c.red}● Error ${c.reset}`
145
+
146
+ const cols = process.stdout.columns || 80
147
+ const prefixWidth = 1 + 8 + 2 + 8 + 2 // 1 space + time (8) + 2 spaces + badge (8) + 2 spaces = 21
148
+
149
+ let displayTitle = String(title || '')
150
+ .replace(/\n/g, ' ')
151
+ .trim()
152
+ const maxTitleLen = Math.max(15, cols - prefixWidth - (detail ? 20 : 3))
153
+ if (displayTitle.length > maxTitleLen) {
154
+ displayTitle = displayTitle.slice(0, Math.max(0, maxTitleLen - 3)) + '...'
155
+ }
156
+
157
+ const remainingForDetail = Math.max(10, cols - prefixWidth - displayTitle.length - 5)
158
+ const rawDetail = String(detail || '')
159
+ .replace(/\n/g, ' ')
160
+ .trim()
161
+ const safeDetail =
162
+ rawDetail.length > remainingForDetail
163
+ ? rawDetail.slice(0, Math.max(0, remainingForDetail - 3)) + '...'
164
+ : rawDetail
165
+
166
+ const cleanDetail = safeDetail ? ` ${c.darkGray}›${c.reset} ${c.gray}${safeDetail}${c.reset}` : ''
167
+ console.log(
168
+ ` ${c.darkGray}${time}${c.reset} ${badge} ${c.white}${displayTitle}${c.reset}${cleanDetail}`
169
+ )
170
+ }
171
+
172
+ export function toggleUpdateModal(config) {
173
+ isUpdateModalOpen = !isUpdateModalOpen
174
+ if (!isUpdateModalOpen) {
175
+ printMonitorHeader(config, isUiActive)
176
+ logActivity('agent', 'Info update ditutup. Monitor kembali ke mode live.')
177
+ } else {
178
+ process.stdout.write('\x1b[r')
179
+ printUpdateModal(updateInfo)
180
+ }
181
+ }
182
+
183
+ export function printUpdateModal(info) {
184
+ const modalWidth = resolveWidth(null, 76)
185
+ const latest = info?.latestVersion || 'terbaru'
186
+ const curr = info?.currentVersion || getCurrentVersion()
187
+ const instruction = info?.instruction || 'npm install -g @mazees/mark@latest'
188
+
189
+ console.log(`\n ${c.bold}${drawDivider('[INFO UPDATE MARK]', modalWidth, c.green)}\n`)
190
+ console.log(
191
+ ` Versi terbaru ${c.bold}${c.cyan}@mazees/mark${c.reset} (${c.green}v${latest}${c.reset}) telah dirilis di npm!`
192
+ )
193
+ console.log(` Versi yang terpasang saat ini: ${c.yellow}v${curr}${c.reset}\n`)
194
+ console.log(
195
+ ` ${c.white}Untuk memperbarui ke versi terbaru, jalankan perintah berikut di terminal:${c.reset}`
196
+ )
197
+ console.log(`\n ${c.bold}${c.green}${instruction}${c.reset}\n`)
198
+ console.log(
199
+ ` ${c.darkGray}Petunjuk: Matikan MARK terlebih dahulu ([q]) sebelum menjalankan perintah update.${c.reset}`
200
+ )
201
+ console.log(`\n ${c.bold}${drawDivider('', modalWidth, c.green)}`)
202
+ console.log(
203
+ ` ${c.gray}Tekan ${c.green}[p]${c.gray} atau ${c.green}[Enter]${c.gray} untuk kembali ke dashboard live...${c.reset}\n`
204
+ )
205
+ }
206
+
207
+ export function toggleJsonInspector(config) {
208
+ isJsonInspectorOpen = !isJsonInspectorOpen
209
+ if (!isJsonInspectorOpen) {
210
+ printMonitorHeader(config, isUiActive)
211
+ logActivity('agent', 'JSON Inspector ditutup. Monitor kembali ke mode live.')
212
+ } else {
213
+ process.stdout.write('\x1b[r')
214
+ printJsonInspector(lastFetchPayload)
215
+ }
216
+ }
217
+
218
+ export function printJsonInspector(payload) {
219
+ const inspectorWidth = resolveWidth(null, 76)
220
+ console.log(
221
+ `\n ${c.bold}${drawDivider('[INFO] AI Request Inspector', inspectorWidth, c.green)}\n`
222
+ )
223
+ console.log(
224
+ ` ${c.gray}Untuk performa maksimal dan bebas lag, payload raksasa kini diinspeksi via:${c.reset}`
225
+ )
226
+ console.log(` ${c.cyan}WebUI DevTools Console (F12) › window.__LAST_AI__${c.reset}\n`)
227
+ if (payload) {
228
+ console.log(` ${c.white}Metadata Permintaan Terakhir:${c.reset}`)
229
+ console.log(
230
+ ` ${c.darkGray}Provider :${c.reset} ${c.teal}${payload.provider || '-'}${c.reset}`
231
+ )
232
+ console.log(
233
+ ` ${c.darkGray}Model :${c.reset} ${c.teal}${payload.model || '-'}${c.reset}`
234
+ )
235
+ console.log(
236
+ ` ${c.darkGray}Messages Count:${c.reset} ${c.teal}${payload.messagesCount ?? '-'}${c.reset}`
237
+ )
238
+ console.log(
239
+ ` ${c.darkGray}Has Tools :${c.reset} ${c.teal}${payload.hasTools ? 'Ya' : 'Tidak'}${c.reset}`
240
+ )
241
+ } else {
242
+ console.log(` ${c.yellow}● Belum ada riwayat aktivitas request AI.${c.reset}`)
243
+ }
244
+ console.log(`\n ${c.bold}${drawDivider('', inspectorWidth, c.green)}\n`)
245
+ }
246
+
247
+ export async function runMonitor(portOverride) {
248
+ let serverPort = portOverride || Number(process.env.PORT) || 3000
249
+ activeServerPort = serverPort
250
+ let serverUrl = `http://localhost:${serverPort}`
251
+ let wsUrl = `ws://localhost:${serverPort}/stream`
252
+
253
+ let isAlive = await new Promise((resolve) => {
254
+ http
255
+ .get(`${serverUrl}/api/health`, (res) => resolve(res.statusCode === 200))
256
+ .on('error', () => resolve(false))
257
+ })
258
+
259
+ if (!isAlive) {
260
+ const serverModule = await import('../server/index.js')
261
+ serverPort = serverModule.activePort || serverPort
262
+ activeServerPort = serverPort
263
+ serverUrl = `http://localhost:${serverPort}`
264
+ wsUrl = `ws://localhost:${serverPort}/stream`
265
+ await new Promise((resolve) => setTimeout(resolve, 600))
266
+ }
267
+
268
+ currentConfig = await (async () => {
269
+ try {
270
+ const res = await fetch(`${serverUrl}/api/config`)
271
+ const data = await res.json()
272
+ return data.config || {}
273
+ const json = await res.json()
274
+ return json.data || json.config || {}
275
+ } catch (_) {
276
+ return {}
277
+ }
278
+ })()
279
+
280
+ printMonitorHeader(currentConfig, isUiActive)
281
+
282
+ logActivity('agent', `MARK Server aktif di port ${serverPort}`)
283
+ logActivity('agent', 'Membuka antarmuka MARK...')
284
+
285
+ // Pengecekan update versi terbaru di latar belakang (non-blocking)
286
+ checkForUpdate()
287
+ .then((info) => {
288
+ if (info && info.hasUpdate) {
289
+ updateInfo = info
290
+ if (!isJsonInspectorOpen && !isUpdateModalOpen) {
291
+ printMonitorHeader(currentConfig, isUiActive)
292
+ logActivity(
293
+ 'agent',
294
+ 'Update Tersedia',
295
+ `v${info.currentVersion} → v${info.latestVersion} (Tekan [p] utk perintah update)`
296
+ )
297
+ }
298
+ }
299
+ })
300
+ .catch(() => {})
301
+
302
+ // Connect WebSocket live streaming
303
+ try {
304
+ const ws = new WebSocket(wsUrl)
305
+ ws.on('open', () => {
306
+ logActivity('agent', 'Core server siap menerima koneksi.')
307
+ })
308
+ ws.on('message', (data) => {
309
+ try {
310
+ const { event, payload } = JSON.parse(data.toString())
311
+ if (event === 'ui:status') {
312
+ const wasActive = isUiActive
313
+ isUiActive = !!payload?.active
314
+ if (wasActive !== isUiActive && !isJsonInspectorOpen) {
315
+ printMonitorHeader(currentConfig, isUiActive)
316
+ if (isUiActive) {
317
+ logActivity('agent', 'MARK terhubung dan siap digunakan.')
318
+ } else {
319
+ logActivity('agent', 'MARK ditutup (mode standby). Tekan [u] untuk membuka kembali.')
320
+ }
321
+ }
322
+ } else if (event === 'config:updated') {
323
+ currentConfig = payload || {}
324
+ if (!isJsonInspectorOpen) {
325
+ printMonitorHeader(currentConfig, isUiActive)
326
+ const providerStr = currentConfig.aiProvider || 'AI'
327
+ const modelStr =
328
+ providerStr === 'custom'
329
+ ? currentConfig.customModel || 'custom'
330
+ : providerStr === 'gemini-web'
331
+ ? currentConfig.geminiWebModel || 'gemini'
332
+ : currentConfig.model || ''
333
+ logActivity('agent', 'Konfigurasi diperbarui', `${providerStr} (${modelStr})`)
334
+ }
335
+ } else if (event === 'ai:fetch') {
336
+ lastFetchPayload = payload
337
+ const info = `[${payload.provider}/${payload.model}] ${payload.messagesCount || 0} msgs${payload.hasTools ? `, ${payload.toolsCount || 0} tools` : ''}`
338
+ logActivity('fetch', `AI Request (${payload.type || 'fetch'})`, info)
339
+ } else if (event === 'agent:thought') {
340
+ logActivity('thought', `Turn ${payload.turn}`, payload.thought)
341
+ } else if (event === 'tool:call') {
342
+ logActivity('tool', payload.tool, payload.query)
343
+ } else if (event === 'tool:result') {
344
+ logActivity('result', payload.tool, payload.observation)
345
+ } else if (event === 'chat:receive') {
346
+ logActivity('agent', 'Pesan diterima', payload.message)
347
+ } else if (event === 'awareness:entry') {
348
+ logActivity('agent', 'Active Window', `[${payload.app}] ${payload.title}`)
349
+ } else if (event === 'browser:preview' && !payload.closed) {
350
+ logActivity('tool', 'Browser Preview', `${payload.title || ''} (${payload.url || ''})`)
351
+ }
352
+ } catch (_) {}
353
+ })
354
+ } catch (_) {}
355
+
356
+ // Restore scroll region saat resize terminal
357
+ process.stdout.on('resize', () => {
358
+ if (isUpdateModalOpen) {
359
+ process.stdout.write('\x1b[r\x1b[2J\x1b[1;1H')
360
+ printUpdateModal(updateInfo)
361
+ } else if (isJsonInspectorOpen) {
362
+ process.stdout.write('\x1b[r\x1b[2J\x1b[1;1H')
363
+ printJsonInspector(lastFetchPayload)
364
+ } else {
365
+ printMonitorHeader(currentConfig, isUiActive)
366
+ }
367
+ })
368
+
369
+ // Pastikan terminal dikembalikan normal saat exit
370
+ process.on('exit', () => {
371
+ process.stdout.write('\x1b[r\x1b[?25h')
372
+ })
373
+
374
+ // Raw Mode Keyboard Listener for quick actions
375
+ if (process.stdin.isTTY) {
376
+ process.stdin.setRawMode(true)
377
+ }
378
+ readline.emitKeypressEvents(process.stdin)
379
+ process.stdin.resume()
380
+
381
+ process.stdin.on('keypress', async (chunk, key) => {
382
+ if (!key) return
383
+
384
+ if (key.name === 'q' || (key.ctrl && key.name === 'c')) {
385
+ process.stdout.write('\x1b[r\x1b[?25h')
386
+ console.log(
387
+ `\n ${c.yellow}●${c.reset} ${c.gray}Mematikan MARK Core Engine. Sampai jumpa!${c.reset}\n`
388
+ )
389
+ closeUI()
390
+ process.exit(0)
391
+ } else if (key.name === 'u' || key.name === 'o') {
392
+ logActivity('agent', 'Membuka MARK...')
393
+ await launchUI({ port: serverPort, mode: 'app' })
394
+ } else if (key.name === 'p') {
395
+ currentConfig = await fetchConfig()
396
+ toggleUpdateModal(currentConfig)
397
+ } else if (key.name === 'j' || key.name === 'd') {
398
+ currentConfig = await fetchConfig()
399
+ toggleJsonInspector(currentConfig)
400
+ } else if (key.name === 'c') {
401
+ currentConfig = await fetchConfig()
402
+ printMonitorHeader(currentConfig, isUiActive)
403
+ logActivity('agent', 'Layar dibersihkan.')
404
+ } else if (isUpdateModalOpen && (key.name === 'return' || key.name === 'escape')) {
405
+ toggleUpdateModal(currentConfig)
406
+ }
407
+ })
408
+ }
409
+
410
+ // Jalankan jika dipanggil mandiri
411
+ if (process.argv[1]?.endsWith('cli/monitor.js')) {
412
+ runMonitor().catch((err) => console.error('[Monitor Fatal Error]:', err))
413
+ }