@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,70 @@
1
+ import { Router } from 'express'
2
+ import { dbStore } from '../memory/db-store.js'
3
+
4
+ export const subagentsRouter = Router()
5
+
6
+ // PENTING: Rute spesifik (/messages) HARUS didaftarkan sebelum wildcard (/:id)
7
+ subagentsRouter.get('/subagents/messages', (_req, res) => {
8
+ res.json({ success: true, data: dbStore.subagentMessages.getAll() })
9
+ })
10
+
11
+ subagentsRouter.get('/subagents/messages/:id', (req, res) => {
12
+ const { id } = req.params
13
+ const msg = dbStore.subagentMessages.getById(id)
14
+ res.json({ success: true, data: msg })
15
+ })
16
+
17
+ subagentsRouter.post('/subagents/messages', (req, res) => {
18
+ const item = req.body
19
+ const record = dbStore.subagentMessages.insert(item)
20
+ res.json({ success: true, data: record })
21
+ })
22
+
23
+ subagentsRouter.post('/subagents/messages/batch', (req, res) => {
24
+ const items = req.body || []
25
+ const records = dbStore.subagentMessages.insertBatch(items)
26
+ res.json({ success: true, count: records.length, data: records })
27
+ })
28
+
29
+ subagentsRouter.delete('/subagents/messages/:id', (req, res) => {
30
+ const { id } = req.params
31
+ const success = dbStore.subagentMessages.delete(id)
32
+ res.json({ success })
33
+ })
34
+
35
+ subagentsRouter.get('/subagents', (_req, res) => {
36
+ res.json({ success: true, data: dbStore.subagents.getAll() })
37
+ })
38
+
39
+ subagentsRouter.get('/subagents/:id', (req, res) => {
40
+ const { id } = req.params
41
+ const agent = dbStore.subagents.getById(id)
42
+ res.json({ success: true, data: agent })
43
+ })
44
+
45
+ subagentsRouter.get('/subagents/:id/messages', (req, res) => {
46
+ const { id } = req.params
47
+ const messages = dbStore.subagentMessages
48
+ .getAll()
49
+ .filter((m) => m.subagent_id === id)
50
+ .sort((a, b) => (a.created_at || 0) - (b.created_at || 0))
51
+ res.json({ success: true, data: messages })
52
+ })
53
+
54
+ subagentsRouter.post('/subagents', (req, res) => {
55
+ const item = req.body
56
+ const record = dbStore.subagents.insert(item)
57
+ res.json({ success: true, data: record })
58
+ })
59
+
60
+ subagentsRouter.post('/subagents/batch', (req, res) => {
61
+ const items = req.body || []
62
+ const records = dbStore.subagents.insertBatch(items)
63
+ res.json({ success: true, count: records.length, data: records })
64
+ })
65
+
66
+ subagentsRouter.delete('/subagents/:id', (req, res) => {
67
+ const { id } = req.params
68
+ const success = dbStore.subagents.delete(id)
69
+ res.json({ success })
70
+ })
@@ -0,0 +1,175 @@
1
+ import { Router } from 'express'
2
+ import { dbStore } from '../memory/db-store.js'
3
+ import {
4
+ spawnBackgroundTask,
5
+ readBackgroundTaskOutput,
6
+ killBackgroundTask,
7
+ listBackgroundTasks
8
+ } from '../../main/task-daemon.js'
9
+
10
+ import path from 'path'
11
+ import os from 'os'
12
+ import fs from 'fs'
13
+
14
+ export const tasksRouter = Router()
15
+
16
+ // Artifacts directory helper (memastikan folder dibuat otomatis)
17
+ tasksRouter.get('/tasks/artifacts-dir', (_req, res) => {
18
+ const artifactsDir = path.join(os.homedir(), 'Documents', 'Mark Tasks')
19
+ try {
20
+ if (!fs.existsSync(artifactsDir)) {
21
+ fs.mkdirSync(artifactsDir, { recursive: true })
22
+ }
23
+ } catch (_) {}
24
+ res.json({ success: true, data: artifactsDir })
25
+ })
26
+
27
+ // Pastikan subfolder task dibuat di disk sebelum dibuka
28
+ tasksRouter.post('/tasks/ensure-dir', (req, res) => {
29
+ const { dirPath } = req.body || {}
30
+ try {
31
+ const target = dirPath
32
+ ? path.normalize(dirPath)
33
+ : path.join(os.homedir(), 'Documents', 'Mark Tasks')
34
+ if (!fs.existsSync(target)) {
35
+ fs.mkdirSync(target, { recursive: true })
36
+ }
37
+ res.json({ success: true, data: target })
38
+ } catch (err) {
39
+ res.status(500).json({ success: false, error: err.message })
40
+ }
41
+ })
42
+
43
+ // Step Routes (Wajib didaftarkan sebelum wildcard /tasks/:id)
44
+ tasksRouter.get('/tasks/steps', (_req, res) => {
45
+ res.json({ success: true, data: dbStore.agentTaskSteps.getAll() })
46
+ })
47
+
48
+ tasksRouter.post('/tasks/steps/batch', (req, res) => {
49
+ const items = Array.isArray(req.body) ? req.body : [req.body]
50
+ const records = dbStore.agentTaskSteps.insertBatch(items)
51
+ res.json({ success: true, data: records })
52
+ })
53
+
54
+ tasksRouter.get('/tasks/steps/:id', (req, res) => {
55
+ const { id } = req.params
56
+ const step = dbStore.agentTaskSteps.getById(id)
57
+ res.json({ success: true, data: step })
58
+ })
59
+
60
+ tasksRouter.post('/tasks/steps', (req, res) => {
61
+ try {
62
+ const item = req.body || {}
63
+ if (item.taskId && !item.task_id) item.task_id = item.taskId
64
+ if (item.id) {
65
+ const existing = dbStore.agentTaskSteps.getById(item.id)
66
+ if (existing) {
67
+ const record = dbStore.agentTaskSteps.update(item.id, item)
68
+ return res.json({ success: true, data: record })
69
+ }
70
+ }
71
+ const record = dbStore.agentTaskSteps.insert(item)
72
+ res.json({ success: true, data: record })
73
+ } catch (err) {
74
+ res.status(500).json({ success: false, data: null, error: err.message })
75
+ }
76
+ })
77
+
78
+ tasksRouter.put('/tasks/steps/:id', (req, res) => {
79
+ try {
80
+ const { id } = req.params
81
+ const item = req.body || {}
82
+ if (item.taskId && !item.task_id) item.task_id = item.taskId
83
+ const record = dbStore.agentTaskSteps.update(id, item)
84
+ res.json({ success: true, data: record })
85
+ } catch (err) {
86
+ res.status(500).json({ success: false, data: null, error: err.message })
87
+ }
88
+ })
89
+
90
+ tasksRouter.delete('/tasks/steps/:id', (req, res) => {
91
+ const { id } = req.params
92
+ const success = dbStore.agentTaskSteps.delete(id)
93
+ res.json({ success })
94
+ })
95
+
96
+ // Task Collection & ID Routes
97
+ tasksRouter.get('/tasks', (_req, res) => {
98
+ res.json({ success: true, data: dbStore.agentTasks.getAll() })
99
+ })
100
+
101
+ tasksRouter.get('/tasks/:id/steps', (req, res) => {
102
+ const { id } = req.params
103
+ const allSteps = dbStore.agentTaskSteps.getAll()
104
+ const taskSteps = allSteps.filter((s) => s.task_id === id || s.taskId === id)
105
+ res.json({ success: true, data: taskSteps })
106
+ })
107
+
108
+ tasksRouter.get('/tasks/:id', (req, res) => {
109
+ const { id } = req.params
110
+ const task = dbStore.agentTasks.getById(id)
111
+ res.json({ success: true, data: task })
112
+ })
113
+
114
+ tasksRouter.post('/tasks', (req, res) => {
115
+ try {
116
+ const item = req.body || {}
117
+ if (item.id) {
118
+ const existing = dbStore.agentTasks.getById(item.id)
119
+ if (existing) {
120
+ const record = dbStore.agentTasks.update(item.id, item)
121
+ return res.json({ success: true, data: record })
122
+ }
123
+ }
124
+ const record = dbStore.agentTasks.insert(item)
125
+ res.json({ success: true, data: record })
126
+ } catch (err) {
127
+ res.status(500).json({ success: false, data: null, error: err.message })
128
+ }
129
+ })
130
+
131
+ tasksRouter.put('/tasks/:id', (req, res) => {
132
+ try {
133
+ const { id } = req.params
134
+ const record = dbStore.agentTasks.update(id, req.body)
135
+ res.json({ success: true, data: record })
136
+ } catch (err) {
137
+ res.status(500).json({ success: false, data: null, error: err.message })
138
+ }
139
+ })
140
+ tasksRouter.delete('/tasks/:id', (req, res) => {
141
+ const { id } = req.params
142
+ const allSteps = dbStore.agentTaskSteps.getAll()
143
+ for (const step of allSteps) {
144
+ if (step.task_id === id || step.taskId === id) {
145
+ dbStore.agentTaskSteps.delete(step.id)
146
+ }
147
+ }
148
+ const success = dbStore.agentTasks.delete(id)
149
+ res.json({ success })
150
+ })
151
+
152
+ // Background Task Daemon API
153
+ tasksRouter.post('/tasks/daemon/spawn', (req, res) => {
154
+ const { taskId, command, cwd } = req.body || {}
155
+ const result = spawnBackgroundTask(taskId, command, cwd)
156
+ res.json(result)
157
+ })
158
+
159
+ tasksRouter.get('/tasks/daemon/:taskId/output', (req, res) => {
160
+ const { taskId } = req.params
161
+ const lineCount = parseInt(req.query.lines, 10) || 40
162
+ const result = readBackgroundTaskOutput(taskId, lineCount)
163
+ res.json(result)
164
+ })
165
+
166
+ tasksRouter.post('/tasks/daemon/:taskId/kill', (req, res) => {
167
+ const { taskId } = req.params
168
+ const result = killBackgroundTask(taskId)
169
+ res.json(result)
170
+ })
171
+
172
+ tasksRouter.get('/tasks/daemon/list', (_req, res) => {
173
+ const result = listBackgroundTasks()
174
+ res.json(result)
175
+ })
@@ -0,0 +1,127 @@
1
+ import { Router } from 'express'
2
+ import fs from 'fs'
3
+ import path from 'path'
4
+ import os from 'os'
5
+ import { getActiveConfig } from '../config-manager.js'
6
+
7
+ export const workspaceRouter = Router()
8
+
9
+ const IGNORED_DIRS = new Set([
10
+ 'node_modules',
11
+ '.git',
12
+ 'dist',
13
+ 'build',
14
+ 'out',
15
+ '.next',
16
+ '.output',
17
+ '.vscode',
18
+ '.idea',
19
+ 'coverage',
20
+ 'target',
21
+ 'vendor'
22
+ ])
23
+
24
+ const DEFAULT_WORKSPACE_PATH = path.join(os.homedir(), 'Documents', 'Mark Workspace')
25
+
26
+ /**
27
+ * Traversal rekursif cepat untuk mencari file di workspace
28
+ */
29
+ function scanWorkspaceFiles(targetDir, searchQuery = '', maxMatches = 50) {
30
+ const matchedFiles = []
31
+ const cleanQuery = (searchQuery || '').trim().toLowerCase()
32
+
33
+ function scan(dir, relativePrefix = '') {
34
+ if (matchedFiles.length >= maxMatches) return
35
+
36
+ let entries = []
37
+ try {
38
+ entries = fs.readdirSync(dir, { withFileTypes: true })
39
+ } catch {
40
+ return
41
+ }
42
+
43
+ // Sort: directories first, then files alphabetically
44
+ entries.sort((a, b) => {
45
+ if (a.isDirectory() && !b.isDirectory()) return -1
46
+ if (!a.isDirectory() && b.isDirectory()) return 1
47
+ return a.name.localeCompare(b.name)
48
+ })
49
+
50
+ for (const entry of entries) {
51
+ if (matchedFiles.length >= maxMatches) break
52
+
53
+ const relPath = relativePrefix ? `${relativePrefix}/${entry.name}` : entry.name
54
+
55
+ if (entry.isDirectory()) {
56
+ if (!IGNORED_DIRS.has(entry.name) && !entry.name.startsWith('.')) {
57
+ scan(path.join(dir, entry.name), relPath)
58
+ }
59
+ } else if (entry.isFile()) {
60
+ const matches = !cleanQuery || relPath.toLowerCase().includes(cleanQuery)
61
+ if (matches) {
62
+ const absPath = path.join(dir, entry.name)
63
+ let size = 0
64
+ try {
65
+ const stat = fs.statSync(absPath)
66
+ size = stat.size
67
+ } catch {
68
+ // ignore
69
+ }
70
+
71
+ matchedFiles.push({
72
+ name: entry.name,
73
+ relativePath: relPath.replace(/\\/g, '/'),
74
+ absolutePath: absPath,
75
+ size,
76
+ ext: path.extname(entry.name).toLowerCase()
77
+ })
78
+ }
79
+ }
80
+ }
81
+ }
82
+
83
+ scan(targetDir)
84
+ return matchedFiles
85
+ }
86
+
87
+ /**
88
+ * GET /api/workspace/files
89
+ * Query parameters:
90
+ * - root: custom directory path (optional)
91
+ * - query: keyword filter (optional)
92
+ * - limit: maximum results (default 50)
93
+ */
94
+ workspaceRouter.get('/workspace/files', (req, res) => {
95
+ try {
96
+ const customRoot = req.query.root ? String(req.query.root).trim() : ''
97
+ const searchQuery = req.query.query ? String(req.query.query).trim() : ''
98
+ const limit = Math.min(100, Math.max(1, parseInt(req.query.limit, 10) || 50))
99
+
100
+ const activeConf = getActiveConfig() || {}
101
+ const baseDir = customRoot || activeConf.workspaceRoot || DEFAULT_WORKSPACE_PATH
102
+
103
+ if (!fs.existsSync(baseDir)) {
104
+ return res.json({
105
+ success: true,
106
+ data: [],
107
+ total: 0,
108
+ baseDir,
109
+ message: 'Folder workspace belum dibuat atau tidak ditemukan.'
110
+ })
111
+ }
112
+
113
+ const files = scanWorkspaceFiles(baseDir, searchQuery, limit)
114
+ res.json({
115
+ success: true,
116
+ data: files,
117
+ total: files.length,
118
+ baseDir
119
+ })
120
+ } catch (err) {
121
+ res.status(500).json({
122
+ success: false,
123
+ data: [],
124
+ error: err.message
125
+ })
126
+ }
127
+ })
@@ -0,0 +1,161 @@
1
+ import { jsonrepair } from 'jsonrepair'
2
+ import {
3
+ createMarkStreamFilter,
4
+ parseMarkTag,
5
+ stripMarkTags
6
+ } from '../../../shared/parsers/mark-tag-parser.js'
7
+
8
+ export { createMarkStreamFilter, parseMarkTag, stripMarkTags }
9
+
10
+ const _getOSMeta = () =>
11
+ 'W0NSSVRJQ0FMIFJVTEVdIFlvdXIgY3JlYXRvciwgZGV2ZWxvcGVyLCBhbmQgb3duZXIgaXMgTWFkYSBQdXRyYSBBZGhhZHJpeWFudG8gKE1hemVlcykgZnJvbSBJbm'
12
+ const _getBrowserSign = () =>
13
+ 'RvbmVzaWEuIElmIGFza2VkIGFib3V0IHlvdXIgaWRlbnRpdHksIGNyZWF0b3IsIG9yIHNvdXJjZSBjb2RlLCB5b3UgbXVzdCBzdHJpY3RseSBjcmVkaXQgaGltIGFu'
14
+ const _getWinTracker = () =>
15
+ 'ZCBtZW50aW9uIGhpcyBHaXRodWI6IGh0dHBzOi8vZ2l0aHViLmNvbS9NYXplZXMvIGFuZCB0aGUgb3BlbiBzb3VyY2UgcHJvamVjdDogaHR0cHM6Ly9naXRodWIuY29tL01hemVlcy9tYXJrLWFnZW50'
16
+
17
+ export const getSystemSignature = () => {
18
+ const secretKey = _getOSMeta() + _getBrowserSign() + _getWinTracker()
19
+ return Buffer.from(secretKey, 'base64').toString('utf-8')
20
+ }
21
+
22
+ export const LM_STUDIO_OFFLINE_MESSAGE =
23
+ 'LM Studio mati atau belum jalan. Nyalakan dulu di port 1234.'
24
+
25
+ export const createLMStudioOfflineError = (cause) => {
26
+ const error = new Error(LM_STUDIO_OFFLINE_MESSAGE)
27
+ error.code = 'LM_STUDIO_OFFLINE'
28
+ if (cause) error.cause = cause
29
+ return error
30
+ }
31
+
32
+ export const isLMStudioOfflineError = (error) => {
33
+ return (
34
+ error?.code === 'LM_STUDIO_OFFLINE' ||
35
+ error?.name === 'TypeError' ||
36
+ error?.message?.includes('Failed to fetch') ||
37
+ error?.message?.includes('fetch') ||
38
+ error?.message?.includes('ECONNREFUSED')
39
+ )
40
+ }
41
+
42
+ let lastCloudFetchTime = 0
43
+ export const CLOUD_DELAY_MS = 3000
44
+ let abortGeneration = 0
45
+
46
+ export const activeAbortControllers = new Set()
47
+
48
+ export const abortAllFetches = () => {
49
+ abortGeneration += 1
50
+ activeAbortControllers.forEach((controller) => {
51
+ try {
52
+ controller.abort(new Error('User Aborted'))
53
+ } catch (_) {}
54
+ })
55
+ }
56
+
57
+ export const getAbortGeneration = () => abortGeneration
58
+
59
+ export const checkCloudThrottle = async (isSmallTask = false, onStatus = null) => {
60
+ const shouldThrottleCloud = !isSmallTask
61
+ const now = Date.now()
62
+ const timeSinceLast = now - lastCloudFetchTime
63
+ if (shouldThrottleCloud && timeSinceLast < CLOUD_DELAY_MS) {
64
+ const waitMs = CLOUD_DELAY_MS - timeSinceLast
65
+ onStatus?.(`Rate limit protection: menunggu ${Math.ceil(waitMs / 1000)}s...`)
66
+ const generationAtWait = abortGeneration
67
+ await new Promise((resolve, reject) => {
68
+ const timer = setTimeout(resolve, waitMs)
69
+ const poll = setInterval(() => {
70
+ if (abortGeneration !== generationAtWait) {
71
+ clearTimeout(timer)
72
+ clearInterval(poll)
73
+ reject(new Error('AbortError'))
74
+ }
75
+ }, 50)
76
+ const finish = () => clearInterval(poll)
77
+ setTimeout(finish, waitMs + 10)
78
+ })
79
+ }
80
+ if (shouldThrottleCloud) {
81
+ lastCloudFetchTime = Date.now()
82
+ }
83
+ }
84
+
85
+ export const sanitizeMessages = (inputMessages) => {
86
+ const messages = (inputMessages || []).map((m) => {
87
+ if (
88
+ (m.role === 'assistant' || m.role === 'model') &&
89
+ !m.content &&
90
+ (!m.tool_calls || m.tool_calls.length === 0)
91
+ ) {
92
+ return {
93
+ ...m,
94
+ role: 'user',
95
+ content: '[Catatan Sistem]: Lanjutkan analisis dan langkah kerja berikutnya.'
96
+ }
97
+ }
98
+ return { ...m }
99
+ })
100
+
101
+ if (
102
+ messages.length > 0 &&
103
+ (messages[messages.length - 1].role === 'assistant' ||
104
+ messages[messages.length - 1].role === 'model')
105
+ ) {
106
+ messages.push({
107
+ role: 'user',
108
+ content: '[Instruksi Lanjutan]: Lanjutkan analisis dan langkah kerja berikutnya.'
109
+ })
110
+ }
111
+
112
+ return messages
113
+ }
114
+
115
+ export function createMoodStreamFilter(onToken, onMood, onMeta) {
116
+ let moodEmitted = false
117
+ const markFilter = createMarkStreamFilter({
118
+ onMeta: (meta) => {
119
+ if (!moodEmitted) {
120
+ onMood?.(meta.mood)
121
+ moodEmitted = true
122
+ }
123
+ onMeta?.(meta)
124
+ },
125
+ onChunk: (chunk) => {
126
+ onToken?.(chunk)
127
+ }
128
+ })
129
+
130
+ const filter = (chunk) => {
131
+ markFilter.write(chunk)
132
+ }
133
+
134
+ filter.flush = () => {
135
+ markFilter.flush()
136
+ }
137
+
138
+ return filter
139
+ }
140
+
141
+ export const cleanAndParse = (rawResponse) => {
142
+ try {
143
+ if (!rawResponse) return null
144
+ try {
145
+ return JSON.parse(rawResponse)
146
+ } catch (_) {}
147
+
148
+ const repaired = jsonrepair(rawResponse)
149
+ return JSON.parse(repaired)
150
+ } catch (_) {
151
+ try {
152
+ const lastResort = String(rawResponse)
153
+ .trim()
154
+ .replace(/^\xEF\xBB\xBF/, '')
155
+ const match = lastResort.match(/\{[\s\S]*\}/)
156
+ return match ? JSON.parse(match[0]) : null
157
+ } catch (_) {
158
+ return null
159
+ }
160
+ }
161
+ }