@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,347 @@
1
+ import readline from 'readline'
2
+ import fs from 'fs'
3
+
4
+ let appVersion = '5.0.0'
5
+ try {
6
+ const pkg = JSON.parse(fs.readFileSync(new URL('../../package.json', import.meta.url), 'utf-8'))
7
+ if (pkg.version) appVersion = pkg.version
8
+ } catch (_) {}
9
+
10
+ /**
11
+ * CLI Theme and Formatting Utilities for MARK
12
+ * Claude Code & Antigravity aesthetic (Zero Emojis, Clean Box Drawing, Developer-grade Typography)
13
+ */
14
+
15
+ export const colors = {
16
+ reset: '\x1b[0m',
17
+ bold: '\x1b[1m',
18
+ dim: '\x1b[2m',
19
+ italic: '\x1b[3m',
20
+ underline: '\x1b[4m',
21
+
22
+ // Foreground
23
+ green: '\x1b[38;2;31;184;84m', // #1fb854 (MARK Primary Green)
24
+ emerald: '\x1b[38;2;16;185;129m',
25
+ teal: '\x1b[38;2;45;212;191m',
26
+ cyan: '\x1b[38;2;56;189;248m',
27
+ blue: '\x1b[38;2;96;165;250m',
28
+ purple: '\x1b[38;2;192;132;252m',
29
+ yellow: '\x1b[38;2;251;191;36m',
30
+ orange: '\x1b[38;2;251;146;60m',
31
+ red: '\x1b[38;2;248;113;113m',
32
+ gray: '\x1b[38;2;148;163;184m',
33
+ darkGray: '\x1b[38;2;71;85;105m',
34
+ white: '\x1b[38;2;241;245;249m',
35
+
36
+ // Background
37
+ bgDark: '\x1b[48;2;15;23;21m',
38
+ bgCard: '\x1b[48;2;25;54;45m'
39
+ }
40
+
41
+ export function stripAnsi(str) {
42
+ if (typeof str !== 'string') return ''
43
+ return str.replace(/\x1b\[[0-9;]*[a-zA-Z]/g, '')
44
+ }
45
+
46
+ export function truncateAnsi(str, maxWidth) {
47
+ if (!str) return ''
48
+ const plain = stripAnsi(str)
49
+ if (plain.length <= maxWidth) return str
50
+ if (maxWidth <= 3) return '.'.repeat(Math.max(1, maxWidth))
51
+
52
+ const targetLen = maxWidth - 3
53
+ let visible = 0
54
+ let result = ''
55
+ let inAnsi = false
56
+
57
+ for (let i = 0; i < str.length; i++) {
58
+ const char = str[i]
59
+ if (char === '\x1b') {
60
+ inAnsi = true
61
+ result += char
62
+ continue
63
+ }
64
+ if (inAnsi) {
65
+ result += char
66
+ if (/[a-zA-Z]/.test(char)) {
67
+ inAnsi = false
68
+ }
69
+ continue
70
+ }
71
+
72
+ result += char
73
+ visible++
74
+ if (visible >= targetLen) {
75
+ result += '...\x1b[0m'
76
+ break
77
+ }
78
+ }
79
+ return result
80
+ }
81
+
82
+ export function resolveWidth(customWidth = null, fallbackMax = 78, min = 40) {
83
+ const cols = process.stdout.columns || 80
84
+ const maxAllowed = Math.max(min, cols - 3)
85
+ if (typeof customWidth === 'number' && customWidth > 0) {
86
+ return Math.min(customWidth, maxAllowed)
87
+ }
88
+ return Math.min(fallbackMax, maxAllowed)
89
+ }
90
+
91
+ export function drawDivider(label = '', width = null, color = colors.darkGray) {
92
+ const w = resolveWidth(width)
93
+ if (!label) {
94
+ return `${color}${'─'.repeat(Math.max(0, w))}${colors.reset}`
95
+ }
96
+ const clean = stripAnsi(label)
97
+ const remain = Math.max(0, w - clean.length - 4)
98
+ return `${color}── ${label} ${'─'.repeat(remain)}${colors.reset}`
99
+ }
100
+
101
+ export function drawBox(
102
+ title = '',
103
+ contentLines = [],
104
+ width = null,
105
+ borderColor = colors.darkGray
106
+ ) {
107
+ const c = colors
108
+ const w = resolveWidth(width, 78)
109
+ const cleanTitle = stripAnsi(title)
110
+
111
+ let topBorder
112
+ if (cleanTitle) {
113
+ const dashCount = Math.max(0, w - cleanTitle.length - 5)
114
+ topBorder = `${borderColor}╭─ ${c.bold}${c.green}${title}${c.reset}${borderColor} ${'─'.repeat(dashCount)}╮${c.reset}`
115
+ } else {
116
+ const dashCount = Math.max(0, w - 3)
117
+ topBorder = `${borderColor}╭─${'─'.repeat(dashCount)}╮${c.reset}`
118
+ }
119
+ const bottomBorder = `${borderColor}╰${'─'.repeat(Math.max(0, w - 2))}╯${c.reset}`
120
+
121
+ console.log(topBorder)
122
+ const innerWidth = Math.max(10, w - 2)
123
+
124
+ // Flatten lines in case content contains embedded newlines
125
+ const flatLines = []
126
+ for (const raw of contentLines) {
127
+ const parts = String(raw ?? '').split(/\r?\n/)
128
+ flatLines.push(...parts)
129
+ }
130
+
131
+ for (const line of flatLines) {
132
+ const safeLine = truncateAnsi(line, innerWidth)
133
+ const padLen = Math.max(0, innerWidth - stripAnsi(safeLine).length)
134
+ console.log(
135
+ `${borderColor}│${c.reset}${safeLine}${' '.repeat(padLen)}${borderColor}│${c.reset}`
136
+ )
137
+ }
138
+ console.log(bottomBorder)
139
+ }
140
+
141
+ export function drawLeftRail(
142
+ title = '',
143
+ contentLines = [],
144
+ width = null,
145
+ borderColor = colors.darkGray
146
+ ) {
147
+ const c = colors
148
+ const w = resolveWidth(width, 78)
149
+ const cleanTitle = stripAnsi(title)
150
+
151
+ let topBorder
152
+ if (cleanTitle) {
153
+ const dashCount = Math.max(0, w - cleanTitle.length - 4)
154
+ topBorder = `${borderColor}┌─ ${c.bold}${c.green}${title}${c.reset}${borderColor} ${'─'.repeat(dashCount)}${c.reset}`
155
+ } else {
156
+ const dashCount = Math.max(0, w - 2)
157
+ topBorder = `${borderColor}┌─${'─'.repeat(dashCount)}${c.reset}`
158
+ }
159
+ const bottomBorder = `${borderColor}└${'─'.repeat(Math.max(0, w - 1))}${c.reset}`
160
+
161
+ console.log(topBorder)
162
+ const innerWidth = Math.max(10, w - 2)
163
+
164
+ const flatLines = []
165
+ for (const raw of contentLines) {
166
+ const parts = String(raw ?? '').split(/\r?\n/)
167
+ flatLines.push(...parts)
168
+ }
169
+
170
+ for (const line of flatLines) {
171
+ const safeLine = truncateAnsi(line, innerWidth)
172
+ console.log(`${borderColor}│${c.reset}${safeLine}`)
173
+ }
174
+ console.log(bottomBorder)
175
+ }
176
+
177
+ export function printHeader(config = {}) {
178
+ const c = colors
179
+ console.clear()
180
+ const provider = config.aiProvider || 'gemini-web'
181
+ const model =
182
+ provider === 'gemini-web'
183
+ ? config.geminiWebModel || 'gemini-3.6-flash'
184
+ : provider === 'custom'
185
+ ? config.customModel || 'default-model'
186
+ : config.model || 'local-model'
187
+ const cwd = process.cwd()
188
+ const termWidth = resolveWidth(null, 78)
189
+ const maxCwd = Math.max(15, termWidth - 18)
190
+ const displayCwd = cwd.length > maxCwd ? '...' + cwd.slice(-(maxCwd - 3)) : cwd
191
+
192
+ const lines = [
193
+ ` ${c.bold}${c.green}● MARK${c.reset} ${c.white}Autonomous Companion${c.reset} ${c.darkGray}[v${appVersion}]${c.reset}`,
194
+ ` ${c.darkGray}Workspace :${c.reset} ${c.gray}${displayCwd}${c.reset}`,
195
+ ` ${c.darkGray}Provider :${c.reset} ${c.cyan}${provider}${c.reset} ${c.darkGray}(${model})${c.reset} ${c.darkGray}|${c.reset} ${c.darkGray}Port:${c.reset} ${c.teal}3000${c.reset}`,
196
+ ` ${c.darkGray}WebUI :${c.reset} ${c.blue}http://localhost:3000${c.reset} ${c.darkGray}[Edge App Mode Ready]${c.reset}`
197
+ ]
198
+
199
+ drawBox('', lines, termWidth, c.darkGray)
200
+
201
+ const cols = process.stdout.columns || 80
202
+ if (cols < 70) {
203
+ console.log(
204
+ ` ${c.darkGray}Cmds:${c.reset} ${c.green}/ui /web /provider /model /memory /status /clear /exit${c.reset}\n`
205
+ )
206
+ } else {
207
+ console.log(
208
+ ` ${c.darkGray}Commands:${c.reset} ${c.green}/ui${c.reset} ${c.darkGray}|${c.reset} ${c.green}/web${c.reset} ${c.darkGray}|${c.reset} ${c.green}/provider${c.reset} ${c.darkGray}|${c.reset} ${c.green}/model${c.reset} ${c.darkGray}|${c.reset} ${c.green}/memory${c.reset} ${c.darkGray}|${c.reset} ${c.green}/status${c.reset} ${c.darkGray}|${c.reset} ${c.green}/clear${c.reset} ${c.darkGray}|${c.reset} ${c.green}/exit${c.reset}\n`
209
+ )
210
+ }
211
+ }
212
+
213
+ export function printThought(thought, turn = 1) {
214
+ const c = colors
215
+ const lines = [` ${c.gray}${thought.trim()}${c.reset}`]
216
+ drawBox(`Thought (Turn ${turn})`, lines, null, c.darkGray)
217
+ console.log()
218
+ }
219
+
220
+ export function printToolCall(tool, query) {
221
+ const c = colors
222
+ const cols = process.stdout.columns || 80
223
+ const maxQuery = Math.max(20, cols - 30)
224
+ const safeQuery =
225
+ query && String(query).length > maxQuery ? String(query).slice(0, maxQuery - 3) + '...' : query
226
+ console.log(
227
+ ` ${c.yellow}⚡ Action${c.reset} › ${c.bold}${c.white}${tool}${c.reset} ${safeQuery ? `${c.darkGray}› ${c.gray}${safeQuery}${c.reset}` : ''}`
228
+ )
229
+ }
230
+
231
+ export function printToolResult(tool, result) {
232
+ const c = colors
233
+ const cols = process.stdout.columns || 80
234
+ const maxLen = Math.max(25, cols - 30)
235
+ const raw = String(result ?? '')
236
+ .trim()
237
+ .replace(/\n/g, ' ')
238
+ const preview = raw.length > maxLen ? raw.slice(0, maxLen - 3) + '...' : raw
239
+ console.log(
240
+ ` ${c.green}✓ Result${c.reset} › ${c.darkGray}[${tool}]${c.reset} ${c.gray}${preview}${c.reset}\n`
241
+ )
242
+ }
243
+
244
+ export function printAssistantAnswer(answer) {
245
+ const c = colors
246
+ console.log(`\n${c.bold}${c.green}Mark ›${c.reset}`)
247
+ console.log(`${c.white}${answer.trim()}${c.reset}\n`)
248
+ }
249
+
250
+ /**
251
+ * Interactive Arrow-Key Navigable Selector
252
+ * Supports Up/Down arrow keys, j/k, Number keys 1-N, Enter to select, and Esc to cancel.
253
+ */
254
+ export async function promptSelect({ title = 'Select Option', options = [], activeId = null }) {
255
+ return new Promise((resolve) => {
256
+ let selectedIndex = options.findIndex((o) => o.id === activeId)
257
+ if (selectedIndex === -1) selectedIndex = 0
258
+
259
+ const width = resolveWidth(null, 76)
260
+ const innerWidth = Math.max(10, width - 2)
261
+ let renderedLines = 0
262
+
263
+ const render = (isFirst = false) => {
264
+ if (!isFirst && renderedLines > 0) {
265
+ process.stdout.write(`\x1b[${renderedLines}A\r`)
266
+ }
267
+
268
+ const cleanTitle = stripAnsi(title)
269
+ const dashCount = Math.max(0, width - cleanTitle.length - 5)
270
+ const topBorder = `${colors.darkGray}╭─ ${colors.bold}${colors.green}${title}${colors.reset}${colors.darkGray} ${'─'.repeat(dashCount)}╮${colors.reset}`
271
+ const bottomBorder = `${colors.darkGray}╰${'─'.repeat(Math.max(0, width - 2))}╯${colors.reset}`
272
+ const hint = ` ${colors.darkGray}Gunakan panah ↑/↓ atau [1-${options.length}] lalu Enter. Esc untuk batal.${colors.reset}`
273
+
274
+ const lines = options.map((opt, i) => {
275
+ const isSelected = i === selectedIndex
276
+ const isCurrent = opt.id === activeId
277
+ const bullet = isCurrent
278
+ ? `${colors.green}●${colors.reset}`
279
+ : `${colors.darkGray}○${colors.reset}`
280
+ const pointer = isSelected ? `${colors.bold}${colors.green}›${colors.reset}` : ' '
281
+ const titleText = isSelected
282
+ ? `${colors.bold}${colors.green}${opt.title}${colors.reset}`
283
+ : `${colors.white}${opt.title}${colors.reset}`
284
+ const descText = `${colors.darkGray}${opt.description || ''}${colors.reset}`
285
+ const num = `${colors.darkGray}[${i + 1}]${colors.reset}`
286
+ const rawLine = ` ${pointer} ${bullet} ${num} ${titleText} ${descText}`
287
+ const safeLine = truncateAnsi(rawLine, innerWidth)
288
+ const padLen = Math.max(0, innerWidth - stripAnsi(safeLine).length)
289
+ return `${colors.darkGray}│${colors.reset}${safeLine}${' '.repeat(padLen)}${colors.darkGray}│${colors.reset}`
290
+ })
291
+
292
+ process.stdout.write(`\x1b[K${topBorder}\n`)
293
+ for (const line of lines) {
294
+ process.stdout.write(`\x1b[K${line}\n`)
295
+ }
296
+ process.stdout.write(`\x1b[K${bottomBorder}\n`)
297
+ process.stdout.write(`\x1b[K${hint}\n`)
298
+
299
+ renderedLines = lines.length + 3
300
+ }
301
+
302
+ process.stdout.write('\x1b[?25l')
303
+
304
+ if (process.stdin.isTTY) {
305
+ process.stdin.setRawMode(true)
306
+ }
307
+ readline.emitKeypressEvents(process.stdin)
308
+ process.stdin.resume()
309
+
310
+ render(true)
311
+
312
+ const onKeypress = (chunk, key) => {
313
+ if (!key) return
314
+
315
+ if (key.name === 'up' || key.name === 'k') {
316
+ selectedIndex = (selectedIndex - 1 + options.length) % options.length
317
+ render()
318
+ } else if (key.name === 'down' || key.name === 'j') {
319
+ selectedIndex = (selectedIndex + 1) % options.length
320
+ render()
321
+ } else if (key.name === 'return' || key.name === 'enter') {
322
+ cleanup()
323
+ resolve(options[selectedIndex].id)
324
+ } else if (key.name === 'escape' || (key.ctrl && key.name === 'c')) {
325
+ cleanup()
326
+ resolve(null)
327
+ } else if (key.name >= '1' && key.name <= String(options.length)) {
328
+ const numIdx = parseInt(key.name, 10) - 1
329
+ if (numIdx >= 0 && numIdx < options.length) {
330
+ selectedIndex = numIdx
331
+ cleanup()
332
+ resolve(options[numIdx].id)
333
+ }
334
+ }
335
+ }
336
+
337
+ const cleanup = () => {
338
+ process.stdin.removeListener('keypress', onKeypress)
339
+ if (process.stdin.isTTY) {
340
+ process.stdin.setRawMode(false)
341
+ }
342
+ process.stdout.write('\x1b[?25h')
343
+ }
344
+
345
+ process.stdin.on('keypress', onKeypress)
346
+ })
347
+ }
@@ -0,0 +1,227 @@
1
+ using System;
2
+ using System.Diagnostics;
3
+ using System.Drawing;
4
+ using System.IO;
5
+ using System.Net.Http;
6
+ using System.Reflection;
7
+ using System.Runtime.InteropServices;
8
+ using System.Text;
9
+ using System.Threading;
10
+ using System.Threading.Tasks;
11
+ using System.Windows.Forms;
12
+
13
+ namespace MarkLauncher
14
+ {
15
+ static class Program
16
+ {
17
+ [DllImport("user32.dll")]
18
+ private static extern bool SetForegroundWindow(IntPtr hWnd);
19
+
20
+ [DllImport("user32.dll")]
21
+ private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
22
+
23
+ private const int SW_RESTORE = 9;
24
+
25
+ private static NotifyIcon _trayIcon;
26
+ private static ContextMenuStrip _trayMenu;
27
+ private static Process _nodeProcess;
28
+ private static readonly int ServerPort = 3000;
29
+ private static string _appDirectory;
30
+ private static string _iconPath;
31
+
32
+ [STAThread]
33
+ static void Main(string[] args)
34
+ {
35
+ // Cegah multiple instance launcher
36
+ bool createdNew;
37
+ using (Mutex mutex = new Mutex(true, "MARK_AI_OS_COMPANION_MUTEX", out createdNew))
38
+ {
39
+ if (!createdNew)
40
+ {
41
+ // Jika sudah berjalan, buka jendela UI
42
+ OpenOrFocusUI();
43
+ return;
44
+ }
45
+
46
+ Application.EnableVisualStyles();
47
+ Application.SetCompatibleTextRenderingDefault(false);
48
+
49
+ _appDirectory = AppDomain.CurrentDomain.BaseDirectory;
50
+ _iconPath = Path.Combine(_appDirectory, "resources", "icon.ico");
51
+
52
+ InitializeTray();
53
+ StartNodeServer();
54
+
55
+ // Buka UI otomatis saat pertama kali start
56
+ Task.Run(async () =>
57
+ {
58
+ await WaitForServerReadyAsync();
59
+ OpenOrFocusUI();
60
+ });
61
+
62
+ Application.Run();
63
+ }
64
+ }
65
+
66
+ private static void InitializeTray()
67
+ {
68
+ _trayMenu = new ContextMenuStrip();
69
+
70
+ var itemOpen = new ToolStripMenuItem("Buka MARK", null, (s, e) => OpenOrFocusUI());
71
+ itemOpen.Font = new Font(itemOpen.Font, FontStyle.Bold);
72
+ _trayMenu.Items.Add(itemOpen);
73
+
74
+ _trayMenu.Items.Add("Buka di Browser", null, (s, e) => OpenInDefaultBrowser());
75
+ _trayMenu.Items.Add("Restart Server", null, (s, e) => RestartNodeServer());
76
+ _trayMenu.Items.Add(new ToolStripSeparator());
77
+ _trayMenu.Items.Add("Keluar", null, (s, e) => ExitApplication());
78
+
79
+ _trayIcon = new NotifyIcon
80
+ {
81
+ Text = "Mark Agent",
82
+ ContextMenuStrip = _trayMenu,
83
+ Visible = true
84
+ };
85
+
86
+ // Load Custom Icon
87
+ if (File.Exists(_iconPath))
88
+ {
89
+ try
90
+ {
91
+ _trayIcon.Icon = new Icon(_iconPath);
92
+ }
93
+ catch
94
+ {
95
+ _trayIcon.Icon = SystemIcons.Application;
96
+ }
97
+ }
98
+ else
99
+ {
100
+ _trayIcon.Icon = SystemIcons.Application;
101
+ }
102
+
103
+ _trayIcon.DoubleClick += (s, e) => OpenOrFocusUI();
104
+ }
105
+
106
+ private static void StartNodeServer()
107
+ {
108
+ try
109
+ {
110
+ // Prioritaskan node runtime lokal jika ada di folder ./node/node.exe, atau gunakan global node
111
+ string localNode = Path.Combine(_appDirectory, "node", "node.exe");
112
+ string nodeExe = File.Exists(localNode) ? localNode : "node.exe";
113
+ string scriptPath = Path.Combine(_appDirectory, "bin", "mark.js");
114
+
115
+ if (!File.Exists(scriptPath))
116
+ {
117
+ scriptPath = Path.Combine(_appDirectory, "src", "server", "index.js");
118
+ }
119
+
120
+ ProcessStartInfo psi = new ProcessStartInfo
121
+ {
122
+ FileName = nodeExe,
123
+ Arguments = string.Format("\"{0}\" --headless", scriptPath),
124
+ WorkingDirectory = _appDirectory,
125
+ UseShellExecute = false,
126
+ CreateNoWindow = true,
127
+ RedirectStandardOutput = false,
128
+ RedirectStandardError = false
129
+ };
130
+
131
+ _nodeProcess = Process.Start(psi);
132
+ }
133
+ catch (Exception ex)
134
+ {
135
+ MessageBox.Show("Gagal menjalankan server MARK: " + ex.Message, "MARK Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
136
+ }
137
+ }
138
+
139
+ private static async Task WaitForServerReadyAsync()
140
+ {
141
+ using (HttpClient client = new HttpClient())
142
+ {
143
+ client.Timeout = TimeSpan.FromSeconds(2);
144
+ for (int i = 0; i < 30; i++)
145
+ {
146
+ try
147
+ {
148
+ var res = await client.GetAsync(string.Format("http://localhost:{0}/api/health", ServerPort));
149
+ if (res.IsSuccessStatusCode) return;
150
+ }
151
+ catch
152
+ {
153
+ // Server belum siap
154
+ }
155
+ await Task.Delay(500);
156
+ }
157
+ }
158
+ }
159
+
160
+ private static void OpenOrFocusUI()
161
+ {
162
+ string url = string.Format("http://localhost:{0}", ServerPort);
163
+ string profileDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "mark-agent", "ui-profile");
164
+
165
+ try
166
+ {
167
+ // Luncurkan Microsoft Edge dalam mode App dengan profil terisolasi MARK
168
+ ProcessStartInfo psi = new ProcessStartInfo
169
+ {
170
+ FileName = "msedge.exe",
171
+ Arguments = string.Format("--app=\"{0}\" --user-data-dir=\"{1}\" --window-size=1280,800 --app-id=mark-ai-companion", url, profileDir),
172
+ UseShellExecute = true
173
+ };
174
+ Process.Start(psi);
175
+ }
176
+ catch
177
+ {
178
+ // Fallback ke default browser
179
+ OpenInDefaultBrowser();
180
+ }
181
+ }
182
+
183
+ private static void OpenInDefaultBrowser()
184
+ {
185
+ try
186
+ {
187
+ Process.Start(new ProcessStartInfo(string.Format("http://localhost:{0}", ServerPort)) { UseShellExecute = true });
188
+ }
189
+ catch { }
190
+ }
191
+
192
+ private static void RestartNodeServer()
193
+ {
194
+ KillNodeProcess();
195
+ Thread.Sleep(500);
196
+ StartNodeServer();
197
+ _trayIcon.ShowBalloonTip(2000, "MARK AI", "Server berhasil direstart.", ToolTipIcon.Info);
198
+ }
199
+
200
+ private static void KillNodeProcess()
201
+ {
202
+ try
203
+ {
204
+ if (_nodeProcess != null && !_nodeProcess.HasExited)
205
+ {
206
+ _nodeProcess.Kill();
207
+ _nodeProcess.Dispose();
208
+ _nodeProcess = null;
209
+ }
210
+ }
211
+ catch { }
212
+ }
213
+
214
+ private static void ExitApplication()
215
+ {
216
+ if (_trayIcon != null)
217
+ {
218
+ _trayIcon.Visible = false;
219
+ _trayIcon.Dispose();
220
+ }
221
+
222
+ KillNodeProcess();
223
+ Application.Exit();
224
+ Environment.Exit(0);
225
+ }
226
+ }
227
+ }