@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,758 @@
1
+ import path from 'path'
2
+ import os from 'os'
3
+ import fs from 'fs'
4
+ import Database from 'better-sqlite3'
5
+
6
+ const CONFIG_DIR = path.join(os.homedir(), '.config', 'mark-agent')
7
+ if (!fs.existsSync(CONFIG_DIR)) {
8
+ fs.mkdirSync(CONFIG_DIR, { recursive: true })
9
+ }
10
+
11
+ const DB_PATH = path.join(CONFIG_DIR, 'mark.db')
12
+
13
+ // Inisialisasi Database SQLite
14
+ export const sqlite = new Database(DB_PATH)
15
+
16
+ // Optimasi performa SQLite (WAL mode, memory temp store, normal sync)
17
+ sqlite.pragma('journal_mode = WAL')
18
+ sqlite.pragma('synchronous = NORMAL')
19
+ sqlite.pragma('temp_store = MEMORY')
20
+
21
+ // Buat Skema Tabel
22
+ sqlite.exec(`
23
+ -- 1. Configuration Store
24
+ CREATE TABLE IF NOT EXISTS config (
25
+ id TEXT PRIMARY KEY,
26
+ data TEXT NOT NULL,
27
+ updated_at INTEGER
28
+ );
29
+
30
+ -- 2. Cognitive Memory Store (MMS)
31
+ CREATE TABLE IF NOT EXISTS memories (
32
+ id TEXT PRIMARY KEY,
33
+ type TEXT DEFAULT 'notes',
34
+ summary TEXT DEFAULT '',
35
+ memory TEXT NOT NULL,
36
+ vector TEXT,
37
+ confidence REAL DEFAULT 1.0,
38
+ created_at INTEGER NOT NULL,
39
+ updated_at INTEGER
40
+ );
41
+
42
+ -- 3. Sessions & Threads
43
+ CREATE TABLE IF NOT EXISTS sessions (
44
+ id TEXT PRIMARY KEY,
45
+ title TEXT DEFAULT 'New Session',
46
+ data TEXT,
47
+ workspace_root TEXT,
48
+ is_auto_mode INTEGER DEFAULT 0,
49
+ timestamp INTEGER NOT NULL,
50
+ created_at INTEGER NOT NULL,
51
+ updated_at INTEGER
52
+ );
53
+
54
+ -- 4. Chat Turns / History
55
+ CREATE TABLE IF NOT EXISTS chat_turns (
56
+ id TEXT PRIMARY KEY,
57
+ session_id TEXT DEFAULT '1',
58
+ session_title TEXT DEFAULT '',
59
+ user_text TEXT NOT NULL,
60
+ ai_text TEXT NOT NULL,
61
+ combined_text TEXT,
62
+ vector TEXT,
63
+ timestamp INTEGER,
64
+ created_at INTEGER,
65
+ updated_at INTEGER
66
+ );
67
+
68
+ -- 5. Chat Archives
69
+ CREATE TABLE IF NOT EXISTS chat_archives (
70
+ id TEXT PRIMARY KEY,
71
+ summary TEXT NOT NULL,
72
+ topic TEXT DEFAULT '',
73
+ vector TEXT,
74
+ timestamp INTEGER NOT NULL
75
+ );
76
+
77
+ -- 6. Knowledge Documents (RAG)
78
+ CREATE TABLE IF NOT EXISTS documents (
79
+ id TEXT PRIMARY KEY,
80
+ doc_name TEXT NOT NULL,
81
+ chunk_index INTEGER DEFAULT 0,
82
+ content TEXT NOT NULL,
83
+ vector TEXT,
84
+ timestamp INTEGER NOT NULL
85
+ );
86
+
87
+ -- 7. Relational Growth 4D
88
+ CREATE TABLE IF NOT EXISTS relationships (
89
+ user_id TEXT PRIMARY KEY,
90
+ warmth REAL DEFAULT 0.5,
91
+ sarcasm_level REAL DEFAULT 0.5,
92
+ trust REAL DEFAULT 0.5,
93
+ energy REAL DEFAULT 0.5,
94
+ obedience REAL DEFAULT 0.8,
95
+ reasoning TEXT,
96
+ new_relational_memory TEXT,
97
+ last_evaluation INTEGER,
98
+ eval_count INTEGER DEFAULT 0,
99
+ last_chat_index INTEGER DEFAULT 0
100
+ );
101
+
102
+ -- 8. Sub-Agents
103
+ CREATE TABLE IF NOT EXISTS subagents (
104
+ id TEXT PRIMARY KEY,
105
+ name TEXT NOT NULL,
106
+ role TEXT DEFAULT '',
107
+ goal TEXT DEFAULT '',
108
+ allowed_tools TEXT,
109
+ status TEXT DEFAULT 'running',
110
+ turn_count INTEGER DEFAULT 0,
111
+ parent_session_id TEXT DEFAULT '1',
112
+ parent_session_title TEXT DEFAULT '',
113
+ final_answer TEXT,
114
+ created_at INTEGER NOT NULL,
115
+ updated_at INTEGER
116
+ );
117
+
118
+ -- 9. Sub-Agent Messages
119
+ CREATE TABLE IF NOT EXISTS subagent_messages (
120
+ id TEXT PRIMARY KEY,
121
+ subagent_id TEXT NOT NULL,
122
+ sender TEXT NOT NULL,
123
+ role TEXT DEFAULT 'assistant',
124
+ content TEXT NOT NULL,
125
+ thought TEXT,
126
+ action TEXT,
127
+ tool_calls TEXT,
128
+ tool_call_id TEXT,
129
+ name TEXT,
130
+ timestamp INTEGER NOT NULL
131
+ );
132
+
133
+ -- 10. Learned Skills
134
+ CREATE TABLE IF NOT EXISTS learned_skills (
135
+ id TEXT PRIMARY KEY,
136
+ name TEXT NOT NULL,
137
+ description TEXT DEFAULT '',
138
+ content TEXT,
139
+ created_at INTEGER NOT NULL,
140
+ updated_at INTEGER
141
+ );
142
+
143
+ -- 11. Agent Tasks
144
+ CREATE TABLE IF NOT EXISTS agent_tasks (
145
+ id TEXT PRIMARY KEY,
146
+ status TEXT DEFAULT 'pending',
147
+ mode TEXT DEFAULT 'ephemeral',
148
+ title TEXT DEFAULT '',
149
+ objective TEXT DEFAULT '',
150
+ current_step_index INTEGER DEFAULT 0,
151
+ active_step_id TEXT,
152
+ constraints TEXT,
153
+ context_summary TEXT,
154
+ artifact_root TEXT,
155
+ retry_count INTEGER DEFAULT 0,
156
+ max_retries INTEGER DEFAULT 2,
157
+ created_at INTEGER NOT NULL,
158
+ updated_at INTEGER,
159
+ completed_at INTEGER,
160
+ error TEXT
161
+ );
162
+
163
+ -- 12. Agent Task Steps
164
+ CREATE TABLE IF NOT EXISTS agent_task_steps (
165
+ id TEXT PRIMARY KEY,
166
+ task_id TEXT NOT NULL,
167
+ step_index INTEGER DEFAULT 0,
168
+ title TEXT DEFAULT '',
169
+ objective TEXT DEFAULT '',
170
+ deliverable TEXT DEFAULT '',
171
+ acceptance_criteria TEXT,
172
+ status TEXT DEFAULT 'pending',
173
+ input_summary TEXT,
174
+ output_summary TEXT,
175
+ artifact_path TEXT,
176
+ validation TEXT,
177
+ content_hash TEXT,
178
+ attempts INTEGER DEFAULT 0,
179
+ started_at INTEGER,
180
+ completed_at INTEGER,
181
+ updated_at INTEGER,
182
+ error TEXT
183
+ );
184
+
185
+ -- 13. Session Compact (Metadata Kompaksi Konteks)
186
+ CREATE TABLE IF NOT EXISTS session_compact (
187
+ session_id TEXT PRIMARY KEY,
188
+ summary_block TEXT,
189
+ last_compacted_message_id TEXT,
190
+ last_compacted_at INTEGER
191
+ );
192
+
193
+ -- Indeks untuk pencarian cepat
194
+ CREATE INDEX IF NOT EXISTS idx_chat_turns_session ON chat_turns(session_id);
195
+ CREATE INDEX IF NOT EXISTS idx_chat_turns_timestamp ON chat_turns(timestamp);
196
+ CREATE INDEX IF NOT EXISTS idx_memories_type ON memories(type);
197
+ CREATE INDEX IF NOT EXISTS idx_subagent_messages_subagent ON subagent_messages(subagent_id);
198
+ CREATE INDEX IF NOT EXISTS idx_agent_task_steps_task ON agent_task_steps(task_id);
199
+ `)
200
+
201
+ // Helper migrasi kolom otomatis jika tabel SQLite sudah ada dari versi sebelumnya
202
+ function ensureTableColumns(tableName, requiredColumns) {
203
+ try {
204
+ const existingCols = sqlite
205
+ .prepare(`PRAGMA table_info(${tableName})`)
206
+ .all()
207
+ .map((c) => c.name)
208
+ for (const [colName, colType] of Object.entries(requiredColumns)) {
209
+ if (!existingCols.includes(colName)) {
210
+ sqlite.exec(`ALTER TABLE ${tableName} ADD COLUMN ${colName} ${colType}`)
211
+ }
212
+ }
213
+ } catch (err) {
214
+ console.warn(`[DB Store] Auto-migration error on ${tableName}:`, err.message)
215
+ }
216
+ }
217
+
218
+ ensureTableColumns('sessions', {
219
+ workspace_root: 'TEXT',
220
+ is_auto_mode: 'INTEGER DEFAULT 0'
221
+ })
222
+
223
+ // Migrasi satu kali jika ada data di kolom legacy workspace
224
+ try {
225
+ sqlite.exec(`
226
+ UPDATE sessions
227
+ SET workspace_root = workspace
228
+ WHERE (workspace_root IS NULL OR workspace_root = '') AND workspace IS NOT NULL AND workspace != ''
229
+ `)
230
+ } catch (err) {
231
+ void err
232
+ }
233
+
234
+ ensureTableColumns('chat_turns', {
235
+ created_at: 'INTEGER',
236
+ updated_at: 'INTEGER'
237
+ })
238
+
239
+ ensureTableColumns('relationships', {
240
+ reasoning: 'TEXT',
241
+ new_relational_memory: 'TEXT',
242
+ last_chat_index: 'INTEGER DEFAULT 0'
243
+ })
244
+
245
+ ensureTableColumns('subagents', {
246
+ allowed_tools: 'TEXT',
247
+ final_answer: 'TEXT',
248
+ parent_session_id: "TEXT DEFAULT '1'",
249
+ parent_session_title: 'TEXT'
250
+ })
251
+
252
+ ensureTableColumns('subagent_messages', {
253
+ thought: 'TEXT',
254
+ action: 'TEXT',
255
+ tool_calls: 'TEXT',
256
+ tool_call_id: 'TEXT',
257
+ name: 'TEXT'
258
+ })
259
+
260
+ ensureTableColumns('agent_tasks', {
261
+ current_step_index: 'INTEGER DEFAULT 0',
262
+ active_step_id: 'TEXT',
263
+ constraints: 'TEXT',
264
+ context_summary: 'TEXT',
265
+ artifact_root: 'TEXT',
266
+ retry_count: 'INTEGER DEFAULT 0',
267
+ max_retries: 'INTEGER DEFAULT 2',
268
+ completed_at: 'INTEGER',
269
+ error: 'TEXT'
270
+ })
271
+
272
+ ensureTableColumns('agent_task_steps', {
273
+ objective: 'TEXT',
274
+ deliverable: 'TEXT',
275
+ acceptance_criteria: 'TEXT',
276
+ input_summary: 'TEXT',
277
+ output_summary: 'TEXT',
278
+ artifact_path: 'TEXT',
279
+ validation: 'TEXT',
280
+ content_hash: 'TEXT',
281
+ attempts: 'INTEGER DEFAULT 0',
282
+ started_at: 'INTEGER',
283
+ completed_at: 'INTEGER',
284
+ error: 'TEXT'
285
+ })
286
+
287
+ ensureTableColumns('session_compact', {
288
+ summary_block: 'TEXT',
289
+ last_compacted_message_id: 'TEXT',
290
+ last_compacted_at: 'INTEGER',
291
+ total_tokens: 'INTEGER DEFAULT 0'
292
+ })
293
+
294
+ /**
295
+ * Normalisasi ID SQLite: Memastikan ID selalu berupa string bersih tanpa pecahan desimal (.0).
296
+ * Menstandarkan seluruh ID (primary key, foreign key, session_id) ke format string tunggal yang seragam.
297
+ */
298
+ export function normalizeSqliteId(id) {
299
+ if (id === null || id === undefined) return ''
300
+ let clean = String(id).trim()
301
+ if (clean.endsWith('.0')) {
302
+ clean = clean.slice(0, -2)
303
+ }
304
+ clean = clean.replace(/^(\d+)\.0+$/, '$1')
305
+ if (clean === '1' || clean === '1.0' || clean === '1.00') {
306
+ clean = '1'
307
+ }
308
+ return clean
309
+ }
310
+
311
+ /**
312
+ * Generic Table Helper untuk menyediakan API CRUD fleksibel
313
+ */
314
+ class SqliteTable {
315
+ constructor(tableName, idCol = 'id') {
316
+ this.tableName = tableName
317
+ this.idCol = idCol
318
+ }
319
+
320
+ _parseJsonFields(row) {
321
+ if (!row) return null
322
+ const res = { ...row }
323
+
324
+ // Normalisasi otomatis snake_case ke camelCase untuk konsistensi di frontend
325
+ for (const key of Object.keys(row)) {
326
+ if (key.includes('_')) {
327
+ const camelKey = this._toCamel(key)
328
+ if (res[camelKey] === undefined) {
329
+ res[camelKey] = row[key]
330
+ }
331
+ }
332
+ }
333
+
334
+ // Normalisasi khusus step_index agar kompatibel timbal balik di frontend (index & stepIndex)
335
+ if (this.tableName === 'agent_task_steps') {
336
+ if (res.step_index !== undefined) {
337
+ if (res.index === undefined) res.index = res.step_index
338
+ if (res.stepIndex === undefined) res.stepIndex = res.step_index
339
+ }
340
+ if (res.task_id !== undefined && res.taskId === undefined) {
341
+ res.taskId = res.task_id
342
+ }
343
+ }
344
+
345
+ // Normalisasi khusus agent_tasks
346
+ if (this.tableName === 'agent_tasks') {
347
+ if (res.active_step_id !== undefined && res.activeStepId === undefined) {
348
+ res.activeStepId = res.active_step_id
349
+ }
350
+ if (res.current_step_index !== undefined && res.currentStepIndex === undefined) {
351
+ res.currentStepIndex = res.current_step_index
352
+ }
353
+ }
354
+
355
+ // Normalisasi khusus sessions: jadikan satu variabel workspaceRoot
356
+ if (this.tableName === 'sessions') {
357
+ res.workspaceRoot = res.workspace_root || res.workspaceRoot || null
358
+ delete res.workspace
359
+ delete res.workspace_root
360
+ }
361
+
362
+ for (const key of Object.keys(res)) {
363
+ if (typeof res[key] === 'string') {
364
+ const str = res[key].trim()
365
+ if (
366
+ (str.startsWith('{') && str.endsWith('}')) ||
367
+ (str.startsWith('[') && str.endsWith(']'))
368
+ ) {
369
+ try {
370
+ res[key] = JSON.parse(str)
371
+ } catch (err) {
372
+ void err
373
+ }
374
+ }
375
+ }
376
+ }
377
+ return res
378
+ }
379
+
380
+ _serializeJsonFields(obj) {
381
+ const res = { ...obj }
382
+ for (const key of Object.keys(res)) {
383
+ if (typeof res[key] === 'object' && res[key] !== null) {
384
+ res[key] = JSON.stringify(res[key])
385
+ }
386
+ }
387
+ return res
388
+ }
389
+
390
+ getAll() {
391
+ const rows = sqlite.prepare(`SELECT * FROM ${this.tableName} ORDER BY rowid ASC`).all()
392
+ return rows.map((r) => this._parseJsonFields(r))
393
+ }
394
+
395
+ getById(id) {
396
+ const cleanId = normalizeSqliteId(id)
397
+ const row = sqlite
398
+ .prepare(`SELECT * FROM ${this.tableName} WHERE ${this.idCol} = ?`)
399
+ .get(cleanId)
400
+ return this._parseJsonFields(row)
401
+ }
402
+
403
+ insert(item) {
404
+ const raw = { ...item }
405
+ // Normalisasi alias primary key lama dari Dexie (pairId -> id)
406
+ let id =
407
+ raw[this.idCol] !== undefined && raw[this.idCol] !== null
408
+ ? raw[this.idCol]
409
+ : raw.id !== undefined && raw.id !== null
410
+ ? raw.id
411
+ : raw.pairId ||
412
+ raw.userId ||
413
+ raw.sessionId ||
414
+ raw.session_id ||
415
+ `id_${Date.now()}_${Math.random().toString(36).slice(2, 7)}`
416
+
417
+ const cleanId = normalizeSqliteId(id)
418
+
419
+ if (this.idCol !== 'id') {
420
+ delete raw.id
421
+ }
422
+ delete raw.pairId // Hapus key lama agar tidak mencoba insert ke kolom yang tidak ada
423
+
424
+ if (raw.sessionId !== undefined && raw.sessionId !== null) {
425
+ raw.sessionId = normalizeSqliteId(raw.sessionId)
426
+ }
427
+ if (raw.session_id !== undefined && raw.session_id !== null) {
428
+ raw.session_id = normalizeSqliteId(raw.session_id)
429
+ }
430
+
431
+ // Penanganan khusus untuk tabel config jika item berupa objek key-value langsung (bukan { id, data })
432
+ if (this.tableName === 'config' && raw.data === undefined) {
433
+ raw.data = { ...raw }
434
+ }
435
+
436
+ // Normalisasi index ke step_index untuk tabel agent_task_steps
437
+ if (this.tableName === 'agent_task_steps') {
438
+ if (raw.index !== undefined && raw.step_index === undefined && raw.stepIndex === undefined) {
439
+ raw.step_index = raw.index
440
+ }
441
+ }
442
+
443
+ // Normalisasi khusus sessions: jadikan satu variabel workspaceRoot
444
+ if (this.tableName === 'sessions') {
445
+ raw.workspaceRoot = raw.workspaceRoot || null
446
+ delete raw.workspace
447
+ delete raw.workspace_root
448
+ }
449
+
450
+ const record = {
451
+ timestamp: raw.timestamp || raw.createdAt || Date.now(),
452
+ createdAt: raw.createdAt || raw.timestamp || Date.now(),
453
+ updatedAt: raw.updatedAt || Date.now(),
454
+ ...raw,
455
+ id: cleanId,
456
+ [this.idCol]: cleanId
457
+ }
458
+
459
+ const serialized = this._serializeJsonFields(record)
460
+ // Filter hanya field yang ada di skema kolom tabel (gunakan Map untuk mencegah duplikasi kolom snake/camel)
461
+ const tableCols = sqlite
462
+ .prepare(`PRAGMA table_info(${this.tableName})`)
463
+ .all()
464
+ .map((c) => c.name)
465
+
466
+ const colMap = new Map()
467
+ for (const [k, v] of Object.entries(serialized)) {
468
+ const col = this._toSnake(k)
469
+ if (tableCols.includes(col)) {
470
+ if (colMap.has(col) && k !== col) {
471
+ const currentVal = colMap.get(col)
472
+ if (currentVal !== null && currentVal !== undefined && currentVal !== '') {
473
+ continue
474
+ }
475
+ }
476
+ colMap.set(col, v)
477
+ }
478
+ }
479
+ if (tableCols.includes(this.idCol)) {
480
+ colMap.set(this.idCol, cleanId)
481
+ }
482
+
483
+ const keys = Array.from(colMap.keys())
484
+ const placeholders = keys.map(() => '?').join(', ')
485
+ const values = Array.from(colMap.values())
486
+
487
+ const stmt = sqlite.prepare(`
488
+ INSERT OR REPLACE INTO ${this.tableName} (${keys.join(', ')})
489
+ VALUES (${placeholders})
490
+ `)
491
+
492
+ stmt.run(...values)
493
+ return record
494
+ }
495
+
496
+ insertBatch(items) {
497
+ if (!Array.isArray(items) || items.length === 0) return []
498
+ const insertMany = sqlite.transaction((rows) => {
499
+ const results = []
500
+ for (const row of rows) {
501
+ results.push(this.insert(row))
502
+ }
503
+ return results
504
+ })
505
+ return insertMany(items)
506
+ }
507
+
508
+ update(id, updates) {
509
+ const existing = this.getById(id)
510
+ if (!existing) return null
511
+
512
+ const normalizedUpdates = { ...updates }
513
+ for (const [k, v] of Object.entries(updates)) {
514
+ const snake = this._toSnake(k)
515
+ const camel = this._toCamel(k)
516
+ normalizedUpdates[snake] = v
517
+ normalizedUpdates[camel] = v
518
+ }
519
+
520
+ const updated = { ...existing, ...normalizedUpdates, updatedAt: Date.now() }
521
+ this.insert(updated)
522
+ return this.getById(id)
523
+ }
524
+
525
+ delete(id) {
526
+ const cleanId = normalizeSqliteId(id)
527
+ const info = sqlite
528
+ .prepare(`DELETE FROM ${this.tableName} WHERE ${this.idCol} = ?`)
529
+ .run(cleanId)
530
+ return info.changes > 0
531
+ }
532
+
533
+ clear() {
534
+ sqlite.prepare(`DELETE FROM ${this.tableName}`).run()
535
+ }
536
+
537
+ count() {
538
+ const res = sqlite.prepare(`SELECT COUNT(*) as count FROM ${this.tableName}`).get()
539
+ return res?.count || 0
540
+ }
541
+
542
+ _toCamel(str) {
543
+ return str.replace(/_([a-z0-9])/g, (_, letter) => letter.toUpperCase())
544
+ }
545
+
546
+ _toSnake(str) {
547
+ // Normalisasi properti umum ke skema SQLite
548
+ const map = {
549
+ sessionId: 'session_id',
550
+ sessionTitle: 'session_title',
551
+ userText: 'user_text',
552
+ aiText: 'ai_text',
553
+ combinedText: 'combined_text',
554
+ createdAt: 'created_at',
555
+ updatedAt: 'updated_at',
556
+ docName: 'doc_name',
557
+ chunkIndex: 'chunk_index',
558
+ userId: 'user_id',
559
+ sarcasmLevel: 'sarcasm_level',
560
+ lastEvaluation: 'last_evaluation',
561
+ evalCount: 'eval_count',
562
+ lastChatIndex: 'last_chat_index',
563
+ turnCount: 'turn_count',
564
+ parentSessionId: 'parent_session_id',
565
+ subagentId: 'subagent_id',
566
+ toolCalls: 'tool_calls',
567
+ toolCallId: 'tool_call_id',
568
+ taskId: 'task_id',
569
+ stepIndex: 'step_index',
570
+ activeStepId: 'active_step_id',
571
+ currentStepIndex: 'current_step_index',
572
+ artifactRoot: 'artifact_root',
573
+ contextSummary: 'context_summary',
574
+ retryCount: 'retry_count',
575
+ maxRetries: 'max_retries',
576
+ completedAt: 'completed_at',
577
+ artifactPath: 'artifact_path',
578
+ contentHash: 'content_hash',
579
+ inputSummary: 'input_summary',
580
+ outputSummary: 'output_summary',
581
+ startedAt: 'started_at',
582
+ acceptanceCriteria: 'acceptance_criteria'
583
+ }
584
+ return map[str] || str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`)
585
+ }
586
+ }
587
+
588
+ /**
589
+ * Export seluruh isi database SQLite ke objek JSON
590
+ */
591
+ export function exportFullDatabase() {
592
+ const tables = {
593
+ config: dbStore.config.getAll(),
594
+ memories: dbStore.memories.getAll(),
595
+ sessions: dbStore.sessions.getAll(),
596
+ chatTurns: dbStore.chatTurns.getAll(),
597
+ chatArchives: dbStore.chatArchives.getAll(),
598
+ documents: dbStore.documents.getAll(),
599
+ relationships: dbStore.relationships.getAll(),
600
+ subagents: dbStore.subagents.getAll(),
601
+ subagentMessages: dbStore.subagentMessages.getAll(),
602
+ learnedSkills: dbStore.learnedSkills.getAll(),
603
+ agentTasks: dbStore.agentTasks.getAll(),
604
+ agentTaskSteps: dbStore.agentTaskSteps.getAll()
605
+ }
606
+
607
+ return {
608
+ app: 'MARK',
609
+ version: '5.0.0',
610
+ exportedAt: new Date().toISOString(),
611
+ tables
612
+ }
613
+ }
614
+
615
+ /**
616
+ * Import/Restore dump JSON (baik format V4 maupun format V5) ke database SQLite
617
+ */
618
+ export function restoreFullDatabase(dumpData, { overwrite = true } = {}) {
619
+ if (!dumpData || typeof dumpData !== 'object') {
620
+ throw new Error('Format data backup tidak valid.')
621
+ }
622
+
623
+ const rawTables = dumpData.tables || dumpData
624
+ const results = {}
625
+
626
+ // Map nama tabel dari Dexie V4 ke skema SQLite V5
627
+ const tableMapping = {
628
+ config: dbStore.config,
629
+ memory: dbStore.memories,
630
+ memories: dbStore.memories,
631
+ sessions: dbStore.sessions,
632
+ chatTurns: dbStore.chatTurns,
633
+ chat_turns: dbStore.chatTurns,
634
+ chatArchive: dbStore.chatArchives,
635
+ chatArchives: dbStore.chatArchives,
636
+ chat_archives: dbStore.chatArchives,
637
+ documents: dbStore.documents,
638
+ relationships: dbStore.relationships,
639
+ subagents: dbStore.subagents,
640
+ subagent_messages: dbStore.subagentMessages,
641
+ subagentMessages: dbStore.subagentMessages,
642
+ learnedSkills: dbStore.learnedSkills,
643
+ learned_skills: dbStore.learnedSkills,
644
+ agentTasks: dbStore.agentTasks,
645
+ agent_tasks: dbStore.agentTasks,
646
+ agentTaskSteps: dbStore.agentTaskSteps,
647
+ agent_task_steps: dbStore.agentTaskSteps,
648
+ sessionCompact: dbStore.sessionCompact,
649
+ session_compact: dbStore.sessionCompact
650
+ }
651
+
652
+ const restoreTransaction = sqlite.transaction(() => {
653
+ for (const [key, items] of Object.entries(rawTables)) {
654
+ const targetStore = tableMapping[key]
655
+ if (targetStore && Array.isArray(items)) {
656
+ if (overwrite) {
657
+ targetStore.clear()
658
+ }
659
+ for (const item of items) {
660
+ targetStore.insert(item)
661
+ }
662
+ results[key] = items.length
663
+ }
664
+ }
665
+
666
+ // Jika dump memuat config, sinkronisasikan juga ke config.json server
667
+ const restoredConfig = rawTables.config
668
+ if (Array.isArray(restoredConfig) && restoredConfig.length > 0) {
669
+ try {
670
+ const confObj = restoredConfig[0]
671
+ const finalConf = confObj.data
672
+ ? typeof confObj.data === 'string'
673
+ ? JSON.parse(confObj.data)
674
+ : confObj.data
675
+ : confObj
676
+ const cfgPath = path.join(CONFIG_DIR, 'config.json')
677
+ fs.writeFileSync(cfgPath, JSON.stringify(finalConf, null, 2), 'utf-8')
678
+ } catch (err) {
679
+ void err
680
+ }
681
+ }
682
+ })
683
+
684
+ restoreTransaction()
685
+ return { success: true, imported: results }
686
+ }
687
+
688
+ /**
689
+ * Reset seluruh data memori dan riwayat AI (semua tabel kecuali tabel 'config')
690
+ */
691
+ export function resetAllExceptConfig() {
692
+ const resetTransaction = sqlite.transaction(() => {
693
+ // 1. Bersihkan tabel memori & percakapan
694
+ dbStore.memories.clear()
695
+ dbStore.sessions.clear()
696
+ dbStore.sessionCompact.clear()
697
+ dbStore.chatTurns.clear()
698
+ dbStore.chatArchives.clear()
699
+ dbStore.documents.clear()
700
+ dbStore.subagents.clear()
701
+ dbStore.subagentMessages.clear()
702
+ dbStore.learnedSkills.clear()
703
+ dbStore.agentTasks.clear()
704
+ dbStore.agentTaskSteps.clear()
705
+
706
+ // 2. Reset hubungan / sifat relasional ke nilai default awal
707
+ dbStore.relationships.clear()
708
+ dbStore.relationships.insert({
709
+ user_id: 'owner',
710
+ warmth: 0.5,
711
+ sarcasm_level: 0.5,
712
+ trust: 0.5,
713
+ energy: 0.5,
714
+ obedience: 0.8,
715
+ reasoning: 'Karakter dan memori AI direset ke pengaturan awal.',
716
+ new_relational_memory: '',
717
+ last_evaluation: null,
718
+ eval_count: 0,
719
+ last_chat_index: 0
720
+ })
721
+
722
+ // 3. Buat sesi awal default
723
+ dbStore.sessions.insert({
724
+ id: '1',
725
+ title: 'Main Thread',
726
+ data: JSON.stringify([]),
727
+ timestamp: Date.now(),
728
+ created_at: Date.now(),
729
+ updated_at: Date.now()
730
+ })
731
+ })
732
+
733
+ resetTransaction()
734
+ return {
735
+ success: true,
736
+ message: 'Seluruh data AI berhasil direset ke kondisi awal (konfigurasi dipertahankan).'
737
+ }
738
+ }
739
+
740
+ export const dbStore = {
741
+ sqlite,
742
+ config: new SqliteTable('config'),
743
+ memories: new SqliteTable('memories'),
744
+ sessions: new SqliteTable('sessions'),
745
+ sessionCompact: new SqliteTable('session_compact', 'session_id'),
746
+ chatTurns: new SqliteTable('chat_turns'),
747
+ chatArchives: new SqliteTable('chat_archives'),
748
+ documents: new SqliteTable('documents'),
749
+ relationships: new SqliteTable('relationships', 'user_id'),
750
+ subagents: new SqliteTable('subagents'),
751
+ subagentMessages: new SqliteTable('subagent_messages'),
752
+ learnedSkills: new SqliteTable('learned_skills'),
753
+ agentTasks: new SqliteTable('agent_tasks'),
754
+ agentTaskSteps: new SqliteTable('agent_task_steps'),
755
+ exportFullDatabase,
756
+ restoreFullDatabase,
757
+ resetAllExceptConfig
758
+ }