@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,265 @@
1
+ import fs from 'fs'
2
+ import path from 'path'
3
+ import os from 'os'
4
+ import matter from 'gray-matter'
5
+ import AdmZip from 'adm-zip'
6
+
7
+ export function getSkillsDirectory() {
8
+ const dir = path.join(os.homedir(), 'Documents', 'Mark Skills')
9
+ if (!fs.existsSync(dir)) {
10
+ fs.mkdirSync(dir, { recursive: true })
11
+ }
12
+ return dir
13
+ }
14
+
15
+ export async function listAllSkills() {
16
+ const dir = getSkillsDirectory()
17
+ const entries = await fs.promises.readdir(dir, { withFileTypes: true })
18
+ const skills = []
19
+
20
+ for (const entry of entries) {
21
+ if (entry.isDirectory()) {
22
+ const skillFolderPath = path.join(dir, entry.name)
23
+ const skillMdPath = path.join(skillFolderPath, 'SKILL.md')
24
+ let name = entry.name
25
+ let description = 'Custom Mark Skill'
26
+ let author = 'User'
27
+ let tags = []
28
+
29
+ if (fs.existsSync(skillMdPath)) {
30
+ try {
31
+ const raw = await fs.promises.readFile(skillMdPath, 'utf-8')
32
+ const parsed = matter(raw)
33
+ if (parsed.data.name) name = parsed.data.name
34
+ if (parsed.data.description) description = parsed.data.description
35
+ if (parsed.data.author) author = parsed.data.author
36
+ if (Array.isArray(parsed.data.tags)) tags = parsed.data.tags
37
+ } catch (_) {}
38
+ }
39
+
40
+ skills.push({
41
+ name,
42
+ folderName: entry.name,
43
+ description,
44
+ author,
45
+ tags,
46
+ path: skillFolderPath,
47
+ hasSkillMd: fs.existsSync(skillMdPath)
48
+ })
49
+ } else if (entry.name.endsWith('.md')) {
50
+ // Auto-migrate standalone .md to folder format
51
+ const cleanName = entry.name.replace('.md', '')
52
+ const folderPath = path.join(dir, cleanName)
53
+ const fullPath = path.join(dir, entry.name)
54
+ if (!fs.existsSync(folderPath)) {
55
+ await fs.promises.mkdir(folderPath, { recursive: true })
56
+ const newFilePath = path.join(folderPath, 'SKILL.md')
57
+ await fs.promises.rename(fullPath, newFilePath)
58
+ }
59
+
60
+ const skillMdPath = path.join(folderPath, 'SKILL.md')
61
+ let name = cleanName
62
+ let description = 'Custom Mark Skill'
63
+ let author = 'User'
64
+ let tags = []
65
+ if (fs.existsSync(skillMdPath)) {
66
+ try {
67
+ const raw = await fs.promises.readFile(skillMdPath, 'utf-8')
68
+ const parsed = matter(raw)
69
+ if (parsed.data.name) name = parsed.data.name
70
+ if (parsed.data.description) description = parsed.data.description
71
+ if (parsed.data.author) author = parsed.data.author
72
+ if (Array.isArray(parsed.data.tags)) tags = parsed.data.tags
73
+ } catch (_) {}
74
+ }
75
+
76
+ skills.push({
77
+ name,
78
+ folderName: cleanName,
79
+ description,
80
+ author,
81
+ tags,
82
+ path: folderPath,
83
+ hasSkillMd: true
84
+ })
85
+ }
86
+ }
87
+ return skills
88
+ }
89
+
90
+ export async function getSkillFileTree(skillFolderName) {
91
+ const dir = getSkillsDirectory()
92
+ const rootSkillPath = path.join(dir, skillFolderName)
93
+ if (!fs.existsSync(rootSkillPath)) return []
94
+
95
+ async function walk(currentPath, relativePath = '') {
96
+ const entries = await fs.promises.readdir(currentPath, { withFileTypes: true })
97
+ const nodes = []
98
+
99
+ for (const entry of entries) {
100
+ const entryRelPath = relativePath ? `${relativePath}/${entry.name}` : entry.name
101
+ const entryFullPath = path.join(currentPath, entry.name)
102
+
103
+ if (entry.isDirectory()) {
104
+ const children = await walk(entryFullPath, entryRelPath)
105
+ nodes.push({
106
+ name: entry.name,
107
+ path: entryRelPath,
108
+ type: 'folder',
109
+ children
110
+ })
111
+ } else {
112
+ nodes.push({
113
+ name: entry.name,
114
+ path: entryRelPath,
115
+ type: 'file'
116
+ })
117
+ }
118
+ }
119
+
120
+ return nodes.sort((a, b) => {
121
+ if (a.type === b.type) return a.name.localeCompare(b.name)
122
+ return a.type === 'folder' ? -1 : 1
123
+ })
124
+ }
125
+
126
+ return await walk(rootSkillPath)
127
+ }
128
+
129
+ export async function readSkillFileContent(skillFolderName, relativeFilePath) {
130
+ const dir = getSkillsDirectory()
131
+ const fullPath = path.resolve(dir, skillFolderName, relativeFilePath)
132
+ const rootSkillPath = path.resolve(dir, skillFolderName)
133
+
134
+ if (!fullPath.startsWith(rootSkillPath)) {
135
+ throw new Error('Akses direktori di luar batas skill dilarang.')
136
+ }
137
+
138
+ if (!fs.existsSync(fullPath)) {
139
+ return ''
140
+ }
141
+ return await fs.promises.readFile(fullPath, 'utf-8')
142
+ }
143
+
144
+ export async function writeSkillFileContent(skillFolderName, relativeFilePath, content) {
145
+ const dir = getSkillsDirectory()
146
+ const fullPath = path.resolve(dir, skillFolderName, relativeFilePath)
147
+ const rootSkillPath = path.resolve(dir, skillFolderName)
148
+
149
+ if (!fullPath.startsWith(rootSkillPath)) {
150
+ throw new Error('Akses direktori di luar batas skill dilarang.')
151
+ }
152
+
153
+ const parentDir = path.dirname(fullPath)
154
+ if (!fs.existsSync(parentDir)) {
155
+ await fs.promises.mkdir(parentDir, { recursive: true })
156
+ }
157
+
158
+ await fs.promises.writeFile(fullPath, content, 'utf-8')
159
+ return true
160
+ }
161
+
162
+ export async function createSkillItem(skillFolderName, relativePath, isFolder = false) {
163
+ const dir = getSkillsDirectory()
164
+ const fullPath = path.resolve(dir, skillFolderName, relativePath)
165
+ const rootSkillPath = path.resolve(dir, skillFolderName)
166
+
167
+ if (!fullPath.startsWith(rootSkillPath)) {
168
+ throw new Error('Akses direktori tidak valid.')
169
+ }
170
+
171
+ if (isFolder) {
172
+ if (!fs.existsSync(fullPath)) {
173
+ await fs.promises.mkdir(fullPath, { recursive: true })
174
+ }
175
+ } else {
176
+ const parent = path.dirname(fullPath)
177
+ if (!fs.existsSync(parent)) {
178
+ await fs.promises.mkdir(parent, { recursive: true })
179
+ }
180
+ if (!fs.existsSync(fullPath)) {
181
+ await fs.promises.writeFile(fullPath, '', 'utf-8')
182
+ }
183
+ }
184
+ return true
185
+ }
186
+
187
+ export async function renameSkillItem(skillFolderName, oldRelativePath, newRelativePath) {
188
+ const dir = getSkillsDirectory()
189
+ const oldPath = path.resolve(dir, skillFolderName, oldRelativePath)
190
+ const newPath = path.resolve(dir, skillFolderName, newRelativePath)
191
+ const rootSkillPath = path.resolve(dir, skillFolderName)
192
+
193
+ if (!oldPath.startsWith(rootSkillPath) || !newPath.startsWith(rootSkillPath)) {
194
+ throw new Error('Akses direktori tidak valid.')
195
+ }
196
+
197
+ if (fs.existsSync(oldPath)) {
198
+ await fs.promises.rename(oldPath, newPath)
199
+ return true
200
+ }
201
+ return false
202
+ }
203
+
204
+ export async function deleteSkillItem(skillFolderName, relativePath) {
205
+ const dir = getSkillsDirectory()
206
+ const fullPath = path.resolve(dir, skillFolderName, relativePath)
207
+ const rootSkillPath = path.resolve(dir, skillFolderName)
208
+
209
+ if (!fullPath.startsWith(rootSkillPath)) {
210
+ throw new Error('Akses direktori tidak valid.')
211
+ }
212
+
213
+ if (fs.existsSync(fullPath)) {
214
+ const stat = await fs.promises.stat(fullPath)
215
+ if (stat.isDirectory()) {
216
+ await fs.promises.rm(fullPath, { recursive: true, force: true })
217
+ } else {
218
+ await fs.promises.unlink(fullPath)
219
+ }
220
+ return true
221
+ }
222
+ return false
223
+ }
224
+
225
+ export async function deleteFullSkill(skillFolderName) {
226
+ const dir = getSkillsDirectory()
227
+ const fullPath = path.resolve(dir, skillFolderName)
228
+ if (fs.existsSync(fullPath)) {
229
+ await fs.promises.rm(fullPath, { recursive: true, force: true })
230
+ return true
231
+ }
232
+ return false
233
+ }
234
+
235
+ export async function installSkillPackage(zipBuffer, overrideName = null) {
236
+ const dir = getSkillsDirectory()
237
+ const zip = new AdmZip(zipBuffer)
238
+ const entries = zip.getEntries()
239
+
240
+ let detectedName = overrideName
241
+ if (!detectedName) {
242
+ const skillEntry = entries.find((e) => e.entryName === 'SKILL.md' || e.entryName.endsWith('/SKILL.md'))
243
+ if (skillEntry) {
244
+ try {
245
+ const text = skillEntry.getData().toString('utf-8')
246
+ const parsed = matter(text)
247
+ if (parsed.data.name) detectedName = parsed.data.name
248
+ } catch (_) {}
249
+ }
250
+ }
251
+
252
+ if (!detectedName) {
253
+ detectedName = `skill-${Date.now()}`
254
+ }
255
+
256
+ const cleanFolderName = detectedName.replace(/[^a-zA-Z0-9-_]/g, '-').toLowerCase()
257
+ const targetFolder = path.join(dir, cleanFolderName)
258
+
259
+ if (!fs.existsSync(targetFolder)) {
260
+ fs.mkdirSync(targetFolder, { recursive: true })
261
+ }
262
+
263
+ zip.extractAllTo(targetFolder, true)
264
+ return { success: true, folderName: cleanFolderName }
265
+ }