@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,380 @@
1
+ # win-action.ps1
2
+ # Native Windows Win32 action executor for MARK PC Automation
3
+ # Supports: click, type, key, scroll, open, list-windows, focus-window
4
+
5
+ param(
6
+ [string]$Action,
7
+ [int]$X = 0,
8
+ [int]$Y = 0,
9
+ [string]$Text = "",
10
+ [string]$Combo = "",
11
+ [string]$Direction = "down",
12
+ [int]$Amount = 3,
13
+ [string]$Target = ""
14
+ )
15
+
16
+ $ErrorActionPreference = "Continue"
17
+ [Console]::OutputEncoding = [System.Text.Encoding]::UTF8
18
+
19
+ Add-Type -AssemblyName System.Windows.Forms
20
+ Add-Type -AssemblyName System.Drawing
21
+
22
+ $code = @"
23
+ using System;
24
+ using System.Runtime.InteropServices;
25
+ using System.Text;
26
+
27
+ public class Win32 {
28
+ [DllImport("user32.dll")]
29
+ public static extern bool SetCursorPos(int X, int Y);
30
+
31
+ [DllImport("user32.dll")]
32
+ public static extern void mouse_event(uint dwFlags, uint dx, uint dy, int dwData, int dwExtraInfo);
33
+
34
+ [DllImport("user32.dll")]
35
+ public static extern IntPtr GetForegroundWindow();
36
+
37
+ [DllImport("user32.dll")]
38
+ public static extern bool SetForegroundWindow(IntPtr hWnd);
39
+
40
+ [DllImport("user32.dll")]
41
+ public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
42
+
43
+ [DllImport("user32.dll", CharSet = CharSet.Unicode)]
44
+ public static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count);
45
+
46
+ [DllImport("user32.dll")]
47
+ public static extern bool EnumWindows(EnumWindowsProc enumProc, IntPtr lParam);
48
+
49
+ [DllImport("user32.dll")]
50
+ public static extern bool IsWindowVisible(IntPtr hWnd);
51
+
52
+ [DllImport("user32.dll")]
53
+ public static extern bool IsIconic(IntPtr hWnd);
54
+
55
+ [DllImport("user32.dll", CharSet = CharSet.Unicode)]
56
+ public static extern int GetWindowTextLength(IntPtr hWnd);
57
+
58
+ public delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);
59
+
60
+ public const uint MOUSEEVENTF_LEFTDOWN = 0x0002;
61
+ public const uint MOUSEEVENTF_LEFTUP = 0x0004;
62
+ public const uint MOUSEEVENTF_RIGHTDOWN = 0x0008;
63
+ public const uint MOUSEEVENTF_RIGHTUP = 0x0010;
64
+ public const uint MOUSEEVENTF_WHEEL = 0x0800;
65
+
66
+ [DllImport("user32.dll")]
67
+ public static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, int dwExtraInfo);
68
+ public const int KEYEVENTF_EXTENDEDKEY = 0x0001;
69
+ public const byte VK_LWIN = 0x5B;
70
+
71
+ public static string ListWindowsJson() {
72
+ StringBuilder json = new StringBuilder();
73
+ json.Append("[");
74
+ bool first = true;
75
+ EnumWindows(delegate(IntPtr hWnd, IntPtr lParam) {
76
+ int len = GetWindowTextLength(hWnd);
77
+ if (len > 0) {
78
+ StringBuilder sb = new StringBuilder(len + 1);
79
+ GetWindowText(hWnd, sb, sb.Capacity);
80
+ string title = sb.ToString();
81
+ if (!string.IsNullOrWhiteSpace(title) && title != "Program Manager" && title != "Default IME" && !title.StartsWith("MSCTFIME")) {
82
+ if (!first) json.Append(",");
83
+ first = false;
84
+ json.Append("{\"hwnd\":").Append(hWnd.ToInt64()).Append(",\"title\":\"").Append(title.Replace("\\", "\\\\").Replace("\"", "\\\"")).Append("\"}");
85
+ }
86
+ }
87
+ return true;
88
+ }, IntPtr.Zero);
89
+ json.Append("]");
90
+ return json.ToString();
91
+ }
92
+
93
+ public static string FocusWindowByTitle(string target) {
94
+ string lowerTarget = target.ToLower();
95
+ bool found = false;
96
+ string foundTitle = "";
97
+ EnumWindows(delegate(IntPtr hWnd, IntPtr lParam) {
98
+ int len = GetWindowTextLength(hWnd);
99
+ if (len > 0) {
100
+ StringBuilder sb = new StringBuilder(len + 1);
101
+ GetWindowText(hWnd, sb, sb.Capacity);
102
+ string title = sb.ToString();
103
+ if (title.ToLower().Contains(lowerTarget)) {
104
+ ShowWindow(hWnd, 9); // SW_RESTORE = 9
105
+ SetForegroundWindow(hWnd);
106
+ found = true;
107
+ foundTitle = title;
108
+ return false;
109
+ }
110
+ }
111
+ return true;
112
+ }, IntPtr.Zero);
113
+ if (found) {
114
+ return "{\"status\":\"success\",\"action\":\"focus-window\",\"title\":\"" + foundTitle.Replace("\\", "\\\\").Replace("\"", "\\\"") + "\"}";
115
+ }
116
+ return "{\"status\":\"error\",\"message\":\"Window not found: " + target.Replace("\\", "\\\\").Replace("\"", "\\\"") + "\"}";
117
+ }
118
+
119
+ public static bool IsMarkWindow(string title) {
120
+ if (string.IsNullOrWhiteSpace(title)) return true;
121
+ string t = title.Trim();
122
+ if (t == "Program Manager" || t == "Default IME" || t.StartsWith("MSCTFIME")) return true;
123
+ string lower = t.ToLower();
124
+ if (lower == "mark" || lower.StartsWith("mark -") || lower.StartsWith("mark_pc_stop") || lower.StartsWith("mark_unblock") || lower.Contains("mark agent") || lower.Contains("mark pc automation")) {
125
+ return true;
126
+ }
127
+ return false;
128
+ }
129
+
130
+ public static void EnsureTargetWindowFocused() {
131
+ IntPtr fg = GetForegroundWindow();
132
+ string fgTitle = "";
133
+ int fgLen = GetWindowTextLength(fg);
134
+ if (fgLen > 0) {
135
+ StringBuilder fgSb = new StringBuilder(fgLen + 1);
136
+ GetWindowText(fg, fgSb, fgSb.Capacity);
137
+ fgTitle = fgSb.ToString();
138
+ }
139
+
140
+ if (!IsMarkWindow(fgTitle)) {
141
+ return;
142
+ }
143
+
144
+ IntPtr target = IntPtr.Zero;
145
+ EnumWindows(delegate(IntPtr hWnd, IntPtr lParam) {
146
+ if (!IsWindowVisible(hWnd) || IsIconic(hWnd)) return true;
147
+ int len = GetWindowTextLength(hWnd);
148
+ if (len <= 0) return true;
149
+ StringBuilder sb = new StringBuilder(len + 1);
150
+ GetWindowText(hWnd, sb, sb.Capacity);
151
+ string title = sb.ToString();
152
+
153
+ if (!IsMarkWindow(title)) {
154
+ target = hWnd;
155
+ return false;
156
+ }
157
+ return true;
158
+ }, IntPtr.Zero);
159
+
160
+ if (target != IntPtr.Zero) {
161
+ SetForegroundWindow(target);
162
+ System.Threading.Thread.Sleep(200);
163
+ }
164
+ }
165
+
166
+ [StructLayout(LayoutKind.Sequential)]
167
+ public struct KEYBDINPUT {
168
+ public ushort wVk;
169
+ public ushort wScan;
170
+ public uint dwFlags;
171
+ public uint time;
172
+ public IntPtr dwExtraInfo;
173
+ }
174
+
175
+ [StructLayout(LayoutKind.Sequential)]
176
+ public struct INPUT {
177
+ public int type;
178
+ public KEYBDINPUT ki;
179
+ }
180
+
181
+ [DllImport("user32.dll", SetLastError = true)]
182
+ public static extern uint SendInput(uint nInputs, INPUT[] pInputs, int cbSize);
183
+
184
+ public const int INPUT_KEYBOARD = 1;
185
+ public const uint KEYEVENTF_KEYUP = 0x0002;
186
+ public const uint KEYEVENTF_UNICODE = 0x0004;
187
+ public const ushort VK_RETURN = 0x0D;
188
+
189
+ public static string TypeTextUnicode(string text) {
190
+ string normalized = text.Replace("\r\n", "\n").Replace("\r", "\n");
191
+ foreach (char c in normalized) {
192
+ if (c == '\n') {
193
+ INPUT[] inputs = new INPUT[2];
194
+ inputs[0].type = INPUT_KEYBOARD;
195
+ inputs[0].ki.wVk = VK_RETURN;
196
+ inputs[0].ki.wScan = 0;
197
+ inputs[0].ki.dwFlags = 0;
198
+
199
+ inputs[1].type = INPUT_KEYBOARD;
200
+ inputs[1].ki.wVk = VK_RETURN;
201
+ inputs[1].ki.wScan = 0;
202
+ inputs[1].ki.dwFlags = KEYEVENTF_KEYUP;
203
+
204
+ SendInput(2, inputs, Marshal.SizeOf(typeof(INPUT)));
205
+ System.Threading.Thread.Sleep(15);
206
+ } else {
207
+ INPUT[] inputs = new INPUT[2];
208
+ inputs[0].type = INPUT_KEYBOARD;
209
+ inputs[0].ki.wVk = 0;
210
+ inputs[0].ki.wScan = (ushort)c;
211
+ inputs[0].ki.dwFlags = KEYEVENTF_UNICODE;
212
+
213
+ inputs[1].type = INPUT_KEYBOARD;
214
+ inputs[1].ki.wVk = 0;
215
+ inputs[1].ki.wScan = (ushort)c;
216
+ inputs[1].ki.dwFlags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP;
217
+
218
+ SendInput(2, inputs, Marshal.SizeOf(typeof(INPUT)));
219
+ System.Threading.Thread.Sleep(8);
220
+ }
221
+ }
222
+ return "{\"status\":\"success\",\"action\":\"type\",\"text\":\"" + text.Replace("\\", "\\\\").Replace("\"", "\\\"").Replace("\r", "\\r").Replace("\n", "\\n") + "\"}";
223
+ }
224
+ }
225
+ "@
226
+ Add-Type -TypeDefinition $code -Language CSharp
227
+
228
+ function Execute-Click {
229
+ [Win32]::SetCursorPos($X, $Y) | Out-Null
230
+ Start-Sleep -Milliseconds 50
231
+ [Win32]::mouse_event([Win32]::MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0)
232
+ Start-Sleep -Milliseconds 30
233
+ [Win32]::mouse_event([Win32]::MOUSEEVENTF_LEFTUP, 0, 0, 0, 0)
234
+ Write-Output "({`"status`":`"success`",`"action`":`"click`",`"x`":$X,`"y`":$Y})".Trim("()")
235
+ }
236
+
237
+ function Execute-DoubleClick {
238
+ [Win32]::SetCursorPos($X, $Y) | Out-Null
239
+ Start-Sleep -Milliseconds 50
240
+ [Win32]::mouse_event([Win32]::MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0)
241
+ Start-Sleep -Milliseconds 30
242
+ [Win32]::mouse_event([Win32]::MOUSEEVENTF_LEFTUP, 0, 0, 0, 0)
243
+ Start-Sleep -Milliseconds 50
244
+ [Win32]::mouse_event([Win32]::MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0)
245
+ Start-Sleep -Milliseconds 30
246
+ [Win32]::mouse_event([Win32]::MOUSEEVENTF_LEFTUP, 0, 0, 0, 0)
247
+ Write-Output "({`"status`":`"success`",`"action`":`"doubleclick`",`"x`":$X,`"y`":$Y})".Trim("()")
248
+ }
249
+
250
+ function Escape-SendKeys {
251
+ param([string]$str)
252
+ if ([string]::IsNullOrEmpty($str)) { return "" }
253
+ $res = ""
254
+ foreach ($char in $str.ToCharArray()) {
255
+ if ("+^%~(){}[]".Contains($char.ToString())) {
256
+ $res += "{$char}"
257
+ } elseif ($char -eq "`n" -or $char -eq "`r") {
258
+ $res += "{ENTER}"
259
+ } else {
260
+ $res += $char
261
+ }
262
+ }
263
+ return $res
264
+ }
265
+
266
+ function Execute-Type {
267
+ [Win32]::EnsureTargetWindowFocused()
268
+ if (-not [string]::IsNullOrEmpty($Text)) {
269
+ $escaped = Escape-SendKeys -str $Text
270
+ try {
271
+ [System.Windows.Forms.SendKeys]::SendWait($escaped)
272
+ Write-Output "({`"status`":`"success`",`"action`":`"type`",`"text`":`"$Text`"})".Trim("()")
273
+ } catch {
274
+ Write-Output '{"status":"error","message":"SendKeys failed for type"}'
275
+ }
276
+ } else {
277
+ Write-Output '{"status":"error","message":"Empty text"}'
278
+ }
279
+ }
280
+
281
+ function Execute-Key {
282
+ [Win32]::EnsureTargetWindowFocused()
283
+ if (-not [string]::IsNullOrEmpty($Combo)) {
284
+ $keys = $Combo.ToLower().Trim()
285
+ $sendStr = ""
286
+
287
+ # Convert common key combos to SendKeys format
288
+ $keys = $keys -replace 'ctrl\+', '^'
289
+ $keys = $keys -replace 'alt\+', '%'
290
+ $keys = $keys -replace 'shift\+', '+'
291
+
292
+ $specialMap = @{
293
+ "enter" = "{ENTER}"
294
+ "tab" = "{TAB}"
295
+ "esc" = "{ESC}"
296
+ "escape" = "{ESC}"
297
+ "backspace" = "{BACKSPACE}"
298
+ "del" = "{DELETE}"
299
+ "delete" = "{DELETE}"
300
+ "up" = "{UP}"
301
+ "down" = "{DOWN}"
302
+ "left" = "{LEFT}"
303
+ "right" = "{RIGHT}"
304
+ "home" = "{HOME}"
305
+ "end" = "{END}"
306
+ "space" = " "
307
+ }
308
+
309
+ if ($keys -eq "win") {
310
+ [Win32]::keybd_event([Win32]::VK_LWIN, 0, 0, 0)
311
+ Start-Sleep -Milliseconds 20
312
+ [Win32]::keybd_event([Win32]::VK_LWIN, 0, [Win32]::KEYEVENTF_KEYUP, 0)
313
+ Write-Output "({`"status`":`"success`",`"action`":`"key`",`"combo`":`"$Combo`"})".Trim("()")
314
+ return
315
+ }
316
+
317
+ if ($specialMap.ContainsKey($keys)) {
318
+ $sendStr = $specialMap[$keys]
319
+ } else {
320
+ $sendStr = $keys
321
+ }
322
+
323
+ try {
324
+ [System.Windows.Forms.SendKeys]::SendWait($sendStr)
325
+ Write-Output "({`"status`":`"success`",`"action`":`"key`",`"combo`":`"$Combo`"})".Trim("()")
326
+ } catch {
327
+ Write-Output "({`"status`":`"error`",`"message`":`"Invalid key combo: $Combo`"})".Trim("()")
328
+ }
329
+ } else {
330
+ Write-Output '{"status":"error","message":"Empty combo"}'
331
+ }
332
+ }
333
+
334
+ function Execute-Scroll {
335
+ $delta = 120 * $Amount
336
+ if ($Direction -eq "down") {
337
+ $delta = -$delta
338
+ }
339
+ [Win32]::mouse_event([Win32]::MOUSEEVENTF_WHEEL, 0, 0, $delta, 0)
340
+ Write-Output "({`"status`":`"success`",`"action`":`"scroll`",`"direction`":`"$Direction`",`"amount`":$Amount})".Trim("()")
341
+ }
342
+
343
+ function Execute-Open {
344
+ if (-not [string]::IsNullOrEmpty($Target)) {
345
+ try {
346
+ Start-Process -FilePath $Target
347
+ Write-Output "({`"status`":`"success`",`"action`":`"open`",`"target`":`"$Target`"})".Trim("()")
348
+ } catch {
349
+ Write-Output "({`"status`":`"error`",`"message`":`"Failed to open app: $Target`"})".Trim("()")
350
+ }
351
+ } else {
352
+ Write-Output '{"status":"error","message":"Empty target"}'
353
+ }
354
+ }
355
+
356
+ function Execute-ListWindows {
357
+ $res = [Win32]::ListWindowsJson()
358
+ Write-Output $res
359
+ }
360
+
361
+ function Execute-FocusWindow {
362
+ if (-not [string]::IsNullOrEmpty($Target)) {
363
+ $res = [Win32]::FocusWindowByTitle($Target)
364
+ Write-Output $res
365
+ } else {
366
+ Write-Output '{"status":"error","message":"Empty target"}'
367
+ }
368
+ }
369
+
370
+ switch ($Action.ToLower()) {
371
+ "click" { Execute-Click }
372
+ "doubleclick" { Execute-DoubleClick }
373
+ "type" { Execute-Type }
374
+ "key" { Execute-Key }
375
+ "scroll" { Execute-Scroll }
376
+ "open" { Execute-Open }
377
+ "list-windows" { Execute-ListWindows }
378
+ "focus-window" { Execute-FocusWindow }
379
+ default { Write-Output '{"status":"error","message":"Unknown action: ' + $Action + '"}' }
380
+ }
@@ -0,0 +1,306 @@
1
+ import fs from 'fs'
2
+ import path from 'path'
3
+ import os from 'os'
4
+ import { pathToFileURL } from 'url'
5
+ import { execSync } from 'child_process'
6
+
7
+ let loadedPlugins = []
8
+ let pluginActionHandlers = new Map()
9
+
10
+ export function getPluginsDirectory() {
11
+ const dir = path.join(os.homedir(), 'Documents', 'Mark Plugins')
12
+ if (!fs.existsSync(dir)) {
13
+ fs.mkdirSync(dir, { recursive: true })
14
+ }
15
+ return dir
16
+ }
17
+
18
+ export const getPluginsDir = getPluginsDirectory
19
+
20
+ export async function loadAllPlugins() {
21
+ const dir = getPluginsDirectory()
22
+ loadedPlugins = []
23
+ pluginActionHandlers.clear()
24
+
25
+ const entries = await fs.promises.readdir(dir, { withFileTypes: true })
26
+ for (const entry of entries) {
27
+ if (entry.isDirectory()) {
28
+ const pluginDir = path.join(dir, entry.name)
29
+ const manifestPath = path.join(pluginDir, 'plugin.json')
30
+ const indexPath = path.join(pluginDir, 'index.js')
31
+
32
+ if (fs.existsSync(manifestPath) && fs.existsSync(indexPath)) {
33
+ try {
34
+ const manifestRaw = await fs.promises.readFile(manifestPath, 'utf-8')
35
+ const manifest = JSON.parse(manifestRaw)
36
+ manifest.folderName = entry.name
37
+ manifest.folderPath = pluginDir
38
+
39
+ const moduleUrl = `${pathToFileURL(indexPath).href}?t=${Date.now()}`
40
+ const module = await import(moduleUrl)
41
+ const handlerInstance = module.default || module
42
+
43
+ const indexContent = await fs.promises.readFile(indexPath, 'utf-8')
44
+
45
+ if (manifest.isEnabled !== false && Array.isArray(manifest.actions)) {
46
+ for (const act of manifest.actions) {
47
+ const actHandler =
48
+ handlerInstance[act.name] ||
49
+ (typeof handlerInstance === 'function' ? handlerInstance : null)
50
+ if (typeof actHandler === 'function') {
51
+ pluginActionHandlers.set(act.name, {
52
+ handler: actHandler,
53
+ pluginName: manifest.name,
54
+ actionName: act.name
55
+ })
56
+ }
57
+
58
+ // Extract function body for Monaco editor
59
+ const searchPatterns = [
60
+ `'${act.name}': async ({ query }) => {`,
61
+ `"${act.name}": async ({ query }) => {`,
62
+ `${act.name}: async ({ query }) => {`,
63
+ `'${act.name}': async (query) => {`,
64
+ `"${act.name}": async (query) => {`,
65
+ `${act.name}: async (query) => {`
66
+ ]
67
+
68
+ let startIdx = -1
69
+ let matchedPatternLen = 0
70
+ for (const pat of searchPatterns) {
71
+ const idx = indexContent.indexOf(pat)
72
+ if (idx !== -1) {
73
+ startIdx = idx
74
+ matchedPatternLen = pat.length
75
+ break
76
+ }
77
+ }
78
+
79
+ if (startIdx !== -1) {
80
+ let i = startIdx + matchedPatternLen
81
+ let openBrackets = 1
82
+ for (; i < indexContent.length; i++) {
83
+ if (indexContent[i] === '{') openBrackets++
84
+ if (indexContent[i] === '}') {
85
+ openBrackets--
86
+ if (openBrackets === 0) break
87
+ }
88
+ }
89
+ const rawCode = indexContent.substring(startIdx + matchedPatternLen, i)
90
+ act.code = rawCode
91
+ .split('\n')
92
+ .map((l) =>
93
+ l.startsWith(' ') ? l.substring(4) : l.startsWith(' ') ? l.substring(2) : l
94
+ )
95
+ .join('\n')
96
+ .trim()
97
+ }
98
+ }
99
+ }
100
+
101
+ loadedPlugins.push(manifest)
102
+ } catch (err) {
103
+ console.error(`[Plugin Loader] Gagal memuat plugin ${entry.name}:`, err)
104
+ }
105
+ }
106
+ }
107
+ }
108
+ return loadedPlugins
109
+ }
110
+
111
+ export const loadPlugins = loadAllPlugins
112
+ export const getLoadedPlugins = () => loadedPlugins
113
+ export const getPluginHandlers = () => Object.fromEntries(pluginActionHandlers.entries())
114
+
115
+ /**
116
+ * Normalisasi query input dari AI/UI menjadi string tunggal bersih
117
+ */
118
+ export function normalizePluginQuery(rawQuery) {
119
+ if (rawQuery === null || rawQuery === undefined) return ''
120
+ if (typeof rawQuery === 'string') return rawQuery
121
+ if (typeof rawQuery === 'number' || typeof rawQuery === 'boolean') return String(rawQuery)
122
+ if (typeof rawQuery === 'object') {
123
+ if (rawQuery.query !== undefined) {
124
+ return typeof rawQuery.query === 'object'
125
+ ? JSON.stringify(rawQuery.query)
126
+ : String(rawQuery.query)
127
+ }
128
+ if (rawQuery.value !== undefined) return String(rawQuery.value)
129
+ if (rawQuery.volume !== undefined) return String(rawQuery.volume)
130
+ if (rawQuery.text !== undefined) return String(rawQuery.text)
131
+ if (rawQuery.prompt !== undefined) return String(rawQuery.prompt)
132
+ if (rawQuery.target !== undefined) return String(rawQuery.target)
133
+ if (rawQuery.input !== undefined) return String(rawQuery.input)
134
+ const vals = Object.values(rawQuery)
135
+ if (vals.length === 1 && typeof vals[0] !== 'object') {
136
+ return String(vals[0])
137
+ }
138
+ return JSON.stringify(rawQuery)
139
+ }
140
+ return String(rawQuery)
141
+ }
142
+
143
+ function findRegisteredAction(actionName) {
144
+ let registered = pluginActionHandlers.get(actionName)
145
+ if (!registered && typeof actionName === 'string') {
146
+ const lowerName = actionName.toLowerCase()
147
+ for (const [key, value] of pluginActionHandlers.entries()) {
148
+ const fullKey = `plugin-${value.pluginName}-${value.actionName}`.toLowerCase()
149
+ if (
150
+ key.toLowerCase() === lowerName ||
151
+ fullKey === lowerName ||
152
+ lowerName.endsWith(`-${key.toLowerCase()}`) ||
153
+ lowerName.endsWith(`_${key.toLowerCase()}`)
154
+ ) {
155
+ return value
156
+ }
157
+ }
158
+ }
159
+ return registered
160
+ }
161
+
162
+ export async function executePluginAction(actionName, query) {
163
+ let registered = findRegisteredAction(actionName)
164
+
165
+ // Lazy reload on cache miss jika plugin baru ditambah ke disk saat runtime
166
+ if (!registered) {
167
+ await loadAllPlugins()
168
+ registered = findRegisteredAction(actionName)
169
+ }
170
+
171
+ if (!registered) {
172
+ return {
173
+ success: false,
174
+ error: `Action plugin '${actionName}' tidak ditemukan atau sedang dinonaktifkan.`
175
+ }
176
+ }
177
+
178
+ try {
179
+ const cleanQuery = normalizePluginQuery(query)
180
+
181
+ // Buat polymorphic payload agar kompatibel dengan handler `{ query }` maupun `(query)` atau direct template literals
182
+ const payload = {
183
+ query: cleanQuery,
184
+ ...(typeof query === 'object' && query !== null ? query : {}),
185
+ toString: () => cleanQuery,
186
+ valueOf: () => cleanQuery,
187
+ [Symbol.toPrimitive]: () => cleanQuery
188
+ }
189
+ payload.query = cleanQuery
190
+
191
+ const result = await registered.handler(payload)
192
+ return { success: true, data: result }
193
+ } catch (err) {
194
+ console.error(`[Plugin Execution Error] ${actionName}:`, err)
195
+ return { success: false, error: err.message }
196
+ }
197
+ }
198
+
199
+ export async function savePluginDefinition(payload) {
200
+ const {
201
+ name,
202
+ displayName,
203
+ description,
204
+ actions = [],
205
+ dependencies = [],
206
+ isEdit = false
207
+ } = payload
208
+ const cleanName = (name || '').replace(/[^a-zA-Z0-9-_]/g, '-').toLowerCase()
209
+ if (!cleanName) {
210
+ throw new Error('Nama plugin wajib diisi.')
211
+ }
212
+
213
+ const dir = getPluginsDirectory()
214
+ const pluginDir = path.join(dir, cleanName)
215
+
216
+ if (!isEdit && fs.existsSync(pluginDir)) {
217
+ throw new Error(`Plugin dengan nama '${cleanName}' sudah ada.`)
218
+ }
219
+
220
+ if (!fs.existsSync(pluginDir)) {
221
+ fs.mkdirSync(pluginDir, { recursive: true })
222
+ }
223
+
224
+ const depsList = Array.isArray(dependencies)
225
+ ? dependencies
226
+ : typeof dependencies === 'string'
227
+ ? dependencies
228
+ .split(',')
229
+ .map((d) => d.trim())
230
+ .filter(Boolean)
231
+ : []
232
+
233
+ const manifestActions = actions.map((act) => ({
234
+ name: (act.name || '').trim().replace(/\s+/g, '_').toLowerCase(),
235
+ description: act.description || '',
236
+ triggerHint: act.triggerHint || '',
237
+ code: act.code || 'return null;'
238
+ }))
239
+
240
+ const manifest = {
241
+ name: cleanName,
242
+ displayName: displayName || cleanName,
243
+ description: description || '',
244
+ version: '1.0.0',
245
+ isEnabled: true,
246
+ dependencies: depsList,
247
+ actions: manifestActions
248
+ }
249
+
250
+ let jsCode = `// Auto-generated Plugin Module for MARK V5\n// Plugin: ${cleanName}\n\nexport default {\n`
251
+ manifest.actions.forEach((act, idx) => {
252
+ jsCode += ` '${act.name}': async ({ query }) => {\n`
253
+ const lines = (act.code || 'return null;').split('\n')
254
+ for (const l of lines) {
255
+ jsCode += ` ${l}\n`
256
+ }
257
+ jsCode += ` }${idx < manifest.actions.length - 1 ? ',' : ''}\n\n`
258
+ })
259
+ jsCode += `};\n`
260
+
261
+ await fs.promises.writeFile(
262
+ path.join(pluginDir, 'plugin.json'),
263
+ JSON.stringify(manifest, null, 2),
264
+ 'utf-8'
265
+ )
266
+ await fs.promises.writeFile(path.join(pluginDir, 'index.js'), jsCode, 'utf-8')
267
+
268
+ if (depsList.length > 0) {
269
+ try {
270
+ if (!fs.existsSync(path.join(pluginDir, 'package.json'))) {
271
+ execSync('npm init -y', { cwd: pluginDir, stdio: 'ignore' })
272
+ }
273
+ execSync(`npm install ${depsList.join(' ')}`, { cwd: pluginDir, stdio: 'ignore' })
274
+ } catch (npmErr) {
275
+ console.error('[Plugin Dependencies] Gagal install npm dependencies:', npmErr)
276
+ }
277
+ }
278
+
279
+ await loadAllPlugins()
280
+ return manifest
281
+ }
282
+
283
+ export async function togglePluginState(pluginName, isEnabled) {
284
+ const dir = getPluginsDirectory()
285
+ const manifestPath = path.join(dir, pluginName, 'plugin.json')
286
+ if (fs.existsSync(manifestPath)) {
287
+ const raw = await fs.promises.readFile(manifestPath, 'utf-8')
288
+ const manifest = JSON.parse(raw)
289
+ manifest.isEnabled = isEnabled
290
+ await fs.promises.writeFile(manifestPath, JSON.stringify(manifest, null, 2), 'utf-8')
291
+ await loadAllPlugins()
292
+ return true
293
+ }
294
+ return false
295
+ }
296
+
297
+ export async function deletePlugin(pluginName) {
298
+ const dir = getPluginsDirectory()
299
+ const pluginDir = path.join(dir, pluginName)
300
+ if (fs.existsSync(pluginDir)) {
301
+ await fs.promises.rm(pluginDir, { recursive: true, force: true })
302
+ await loadAllPlugins()
303
+ return true
304
+ }
305
+ return false
306
+ }