@hasna/mementos 0.14.18 → 0.14.20

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.
package/dist/mcp/index.js CHANGED
@@ -11557,6 +11557,7 @@ CREATE TABLE IF NOT EXISTS machines (
11557
11557
  name TEXT NOT NULL UNIQUE,
11558
11558
  hostname TEXT NOT NULL,
11559
11559
  platform TEXT NOT NULL DEFAULT 'unknown',
11560
+ is_primary INTEGER NOT NULL DEFAULT 0,
11560
11561
  created_at TEXT NOT NULL DEFAULT (datetime('now')),
11561
11562
  last_seen_at TEXT NOT NULL DEFAULT (datetime('now'))
11562
11563
  );
@@ -11936,33 +11937,44 @@ CREATE INDEX IF NOT EXISTS idx_memories_sequence_group ON memories(sequence_grou
11936
11937
  INSERT OR IGNORE INTO _migrations (id) VALUES (32);
11937
11938
  `,
11938
11939
  `
11939
- ALTER TABLE machines ADD COLUMN is_primary INTEGER NOT NULL DEFAULT 0;
11940
- CREATE INDEX IF NOT EXISTS idx_machines_primary ON machines(is_primary);
11941
- CREATE TRIGGER IF NOT EXISTS machines_single_primary_insert
11942
- AFTER INSERT ON machines
11943
- WHEN NEW.is_primary = 1
11944
- BEGIN
11945
- UPDATE machines
11946
- SET is_primary = 0,
11947
- last_seen_at = COALESCE(NEW.last_seen_at, datetime('now'))
11948
- WHERE id != NEW.id AND is_primary = 1;
11949
- END;
11950
- CREATE TRIGGER IF NOT EXISTS machines_single_primary_update
11951
- AFTER UPDATE OF is_primary ON machines
11952
- WHEN NEW.is_primary = 1
11953
- BEGIN
11954
- UPDATE machines
11955
- SET is_primary = 0,
11956
- last_seen_at = COALESCE(NEW.last_seen_at, datetime('now'))
11957
- WHERE id != NEW.id AND is_primary = 1;
11958
- END;
11959
- CREATE TRIGGER IF NOT EXISTS machines_prevent_delete_primary
11960
- BEFORE DELETE ON machines
11961
- WHEN OLD.is_primary = 1
11962
- BEGIN
11963
- SELECT RAISE(ABORT, 'Primary machine cannot be deleted');
11964
- END;
11965
- INSERT OR IGNORE INTO _migrations (id) VALUES (33);
11940
+ CREATE TABLE IF NOT EXISTS tasks (
11941
+ id TEXT PRIMARY KEY,
11942
+ subject TEXT NOT NULL,
11943
+ description TEXT DEFAULT '',
11944
+ status TEXT NOT NULL DEFAULT 'pending' CHECK(status IN ('pending', 'in_progress', 'completed', 'failed', 'cancelled')),
11945
+ priority TEXT NOT NULL DEFAULT 'medium' CHECK(priority IN ('critical', 'high', 'medium', 'low')),
11946
+ tags TEXT NOT NULL DEFAULT '[]',
11947
+ assigned_agent_id TEXT REFERENCES agents(id) ON DELETE SET NULL,
11948
+ project_id TEXT REFERENCES projects(id) ON DELETE SET NULL,
11949
+ session_id TEXT,
11950
+ parent_task_id TEXT REFERENCES tasks(id) ON DELETE SET NULL,
11951
+ metadata TEXT NOT NULL DEFAULT '{}',
11952
+ progress REAL NOT NULL DEFAULT 0 CHECK(progress >= 0 AND progress <= 1),
11953
+ due_at TEXT,
11954
+ started_at TEXT,
11955
+ completed_at TEXT,
11956
+ failed_at TEXT,
11957
+ error TEXT,
11958
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
11959
+ updated_at TEXT NOT NULL DEFAULT (datetime('now'))
11960
+ );
11961
+ CREATE INDEX IF NOT EXISTS idx_tasks_status ON tasks(status);
11962
+ CREATE INDEX IF NOT EXISTS idx_tasks_priority ON tasks(priority);
11963
+ CREATE INDEX IF NOT EXISTS idx_tasks_agent ON tasks(assigned_agent_id);
11964
+ CREATE INDEX IF NOT EXISTS idx_tasks_project ON tasks(project_id);
11965
+ CREATE INDEX IF NOT EXISTS idx_tasks_session ON tasks(session_id);
11966
+ CREATE INDEX IF NOT EXISTS idx_tasks_parent ON tasks(parent_task_id);
11967
+
11968
+ CREATE TABLE IF NOT EXISTS task_comments (
11969
+ id TEXT PRIMARY KEY,
11970
+ task_id TEXT NOT NULL REFERENCES tasks(id) ON DELETE CASCADE,
11971
+ agent_id TEXT REFERENCES agents(id) ON DELETE SET NULL,
11972
+ body TEXT NOT NULL,
11973
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
11974
+ );
11975
+ CREATE INDEX IF NOT EXISTS idx_task_comments_task ON task_comments(task_id);
11976
+ CREATE INDEX IF NOT EXISTS idx_task_comments_agent ON task_comments(agent_id);
11977
+ INSERT OR IGNORE INTO _migrations (id) VALUES (34);
11966
11978
  `
11967
11979
  ];
11968
11980
  });
@@ -12617,7 +12629,7 @@ function createMemory(input, dedupeMode = "merge", db) {
12617
12629
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 'active', 0, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 0, 1, ?, ?, ?, ?, ?, ?)`, [
12618
12630
  id,
12619
12631
  input.key,
12620
- input.value,
12632
+ safeValue,
12621
12633
  input.category || "knowledge",
12622
12634
  input.scope || "private",
12623
12635
  input.summary || null,
@@ -13091,8 +13103,12 @@ function parseMachine(row) {
13091
13103
  is_primary: Boolean(row.is_primary)
13092
13104
  };
13093
13105
  }
13106
+ function normalizeHostname(host) {
13107
+ return host.replace(/\.(local|lan|home|internal)$/i, "");
13108
+ }
13094
13109
  function registerMachine(name, db = getDatabase()) {
13095
- const host = hostname2();
13110
+ const rawHost = hostname2();
13111
+ const host = normalizeHostname(rawHost);
13096
13112
  const plat = platform2();
13097
13113
  const machineName = name?.trim() || host;
13098
13114
  const existing = parseMachine(db.query("SELECT * FROM machines WHERE hostname = ?").get(host));
@@ -13156,7 +13172,7 @@ function touchMachine(id, db = getDatabase()) {
13156
13172
  db.run("UPDATE machines SET last_seen_at = ? WHERE id = ?", [now(), id]);
13157
13173
  }
13158
13174
  function getCurrentMachineId(db = getDatabase()) {
13159
- const host = hostname2();
13175
+ const host = normalizeHostname(hostname2());
13160
13176
  const m = db.query("SELECT id FROM machines WHERE hostname = ?").get(host);
13161
13177
  if (m) {
13162
13178
  touchMachine(m.id, db);
@@ -13879,6 +13895,10 @@ function buildFilterConditions(filter) {
13879
13895
  params.push(tag);
13880
13896
  }
13881
13897
  }
13898
+ if (filter.namespace) {
13899
+ conditions.push("m.namespace = ?");
13900
+ params.push(filter.namespace);
13901
+ }
13882
13902
  return { conditions, params };
13883
13903
  }
13884
13904
  function searchWithFts5(d, query, queryLower, filter, graphBoostedIds) {
@@ -23126,6 +23146,7 @@ function resolveProjectId(agentId, explicitProjectId) {
23126
23146
 
23127
23147
  // src/mcp/tools/memory-crud.ts
23128
23148
  init_database();
23149
+ init_machines();
23129
23150
  init_search();
23130
23151
 
23131
23152
  // src/lib/duration.ts
@@ -23314,6 +23335,11 @@ function registerMemoryCrudTools(server) {
23314
23335
  }
23315
23336
  const dedupeMode = conflict ?? "merge";
23316
23337
  const conflictStrategy = args.conflict_strategy ?? "last_writer_wins";
23338
+ if (!input.machine_id) {
23339
+ try {
23340
+ input.machine_id = getCurrentMachineId();
23341
+ } catch {}
23342
+ }
23317
23343
  if (conflictStrategy === "reject" && input.agent_id) {
23318
23344
  const db = getDatabase();
23319
23345
  try {
@@ -26783,7 +26809,14 @@ Created: ${project.created_at}`
26783
26809
  const machines = listMachines();
26784
26810
  return { content: [{ type: "text", text: JSON.stringify(machines) }] };
26785
26811
  } catch (e) {
26786
- return { content: [{ type: "text", text: formatError3(e) }], isError: true };
26812
+ try {
26813
+ const machines = listMachines();
26814
+ return { content: [{ type: "text", text: JSON.stringify(machines) + `
26815
+
26816
+ (Note: Cloud pull failed, showing local data only)` }] };
26817
+ } catch {
26818
+ return { content: [{ type: "text", text: formatError3(e) }], isError: true };
26819
+ }
26787
26820
  }
26788
26821
  });
26789
26822
  server.tool("rename_machine", "Rename a machine by its ID or current name.", { id: exports_external2.string().describe("Machine ID or name"), new_name: exports_external2.string() }, async (args) => {
@@ -0,0 +1,397 @@
1
+ // @bun
2
+ // src/sdk/index.ts
3
+ class MementosError extends Error {
4
+ status;
5
+ details;
6
+ constructor(message, status, details) {
7
+ super(message);
8
+ this.status = status;
9
+ this.details = details;
10
+ this.name = "MementosError";
11
+ }
12
+ }
13
+
14
+ class MementosClient {
15
+ baseUrl;
16
+ _fetch;
17
+ constructor(config = {}) {
18
+ this.baseUrl = (config.baseUrl ?? "http://localhost:19428").replace(/\/$/, "");
19
+ this._fetch = config.fetch ?? globalThis.fetch.bind(globalThis);
20
+ }
21
+ static fromEnv(overrides = {}) {
22
+ const envUrl = typeof process !== "undefined" ? process.env?.["MEMENTOS_URL"] : undefined;
23
+ const baseUrl = envUrl ?? "http://localhost:19428";
24
+ return new MementosClient({ baseUrl, ...overrides });
25
+ }
26
+ async request(method, path, body, query) {
27
+ let url = `${this.baseUrl}${path}`;
28
+ if (query) {
29
+ const params = new URLSearchParams;
30
+ for (const [k, v] of Object.entries(query)) {
31
+ if (v !== undefined)
32
+ params.set(k, String(v));
33
+ }
34
+ const qs = params.toString();
35
+ if (qs)
36
+ url += `?${qs}`;
37
+ }
38
+ const res = await this._fetch(url, {
39
+ method,
40
+ headers: body !== undefined ? { "Content-Type": "application/json" } : {},
41
+ body: body !== undefined ? JSON.stringify(body) : undefined
42
+ });
43
+ if (!res.ok) {
44
+ let errBody = {};
45
+ try {
46
+ errBody = await res.json();
47
+ } catch {}
48
+ throw new MementosError(errBody.error ?? `HTTP ${res.status}`, res.status, errBody.details);
49
+ }
50
+ if (res.status === 204)
51
+ return;
52
+ return res.json();
53
+ }
54
+ get(path, query) {
55
+ return this.request("GET", path, undefined, query);
56
+ }
57
+ post(path, body) {
58
+ return this.request("POST", path, body);
59
+ }
60
+ patch(path, body) {
61
+ return this.request("PATCH", path, body);
62
+ }
63
+ delete(path) {
64
+ return this.request("DELETE", path);
65
+ }
66
+ async listMemories(filter = {}) {
67
+ const q = {};
68
+ if (filter.scope)
69
+ q["scope"] = filter.scope;
70
+ if (filter.category)
71
+ q["category"] = filter.category;
72
+ if (filter.tags?.length)
73
+ q["tags"] = filter.tags.join(",");
74
+ if (filter.min_importance !== undefined)
75
+ q["min_importance"] = filter.min_importance;
76
+ if (filter.pinned !== undefined)
77
+ q["pinned"] = filter.pinned;
78
+ if (filter.agent_id)
79
+ q["agent_id"] = filter.agent_id;
80
+ if (filter.project_id)
81
+ q["project_id"] = filter.project_id;
82
+ if (filter.session_id)
83
+ q["session_id"] = filter.session_id;
84
+ if (filter.namespace)
85
+ q["namespace"] = filter.namespace;
86
+ if (filter.status)
87
+ q["status"] = filter.status;
88
+ if (filter.limit !== undefined)
89
+ q["limit"] = filter.limit;
90
+ if (filter.offset !== undefined)
91
+ q["offset"] = filter.offset;
92
+ if (filter.fields?.length)
93
+ q["fields"] = filter.fields.join(",");
94
+ return this.get("/api/memories", q);
95
+ }
96
+ getStats() {
97
+ return this.get("/api/memories/stats");
98
+ }
99
+ getHealth() {
100
+ return this.get("/api/health");
101
+ }
102
+ getReport(options) {
103
+ return this.get("/api/report", options);
104
+ }
105
+ getStaleMemories(options) {
106
+ return this.get("/api/memories/stale", options);
107
+ }
108
+ getActivity(options) {
109
+ return this.get("/api/activity", options);
110
+ }
111
+ searchMemories(input) {
112
+ const body = typeof input === "string" ? { query: input } : input;
113
+ return this.post("/api/memories/search", body);
114
+ }
115
+ exportMemories(input = {}) {
116
+ return this.post("/api/memories/export", input);
117
+ }
118
+ importMemories(input) {
119
+ return this.post("/api/memories/import", input);
120
+ }
121
+ cleanExpired() {
122
+ return this.post("/api/memories/clean");
123
+ }
124
+ extractFromSession(input) {
125
+ return this.post("/api/memories/extract", input);
126
+ }
127
+ saveMemory(input) {
128
+ return this.post("/api/memories", input);
129
+ }
130
+ getMemory(id) {
131
+ return this.get(`/api/memories/${id}`);
132
+ }
133
+ getMemoryVersions(id) {
134
+ return this.get(`/api/memories/${id}/versions`);
135
+ }
136
+ updateMemory(id, input) {
137
+ return this.patch(`/api/memories/${id}`, input);
138
+ }
139
+ deleteMemory(id) {
140
+ return this.delete(`/api/memories/${id}`);
141
+ }
142
+ listAgents() {
143
+ return this.get("/api/agents");
144
+ }
145
+ registerAgent(input) {
146
+ return this.post("/api/agents", input);
147
+ }
148
+ getAgent(idOrName) {
149
+ return this.get(`/api/agents/${idOrName}`);
150
+ }
151
+ updateAgent(idOrName, updates) {
152
+ return this.patch(`/api/agents/${idOrName}`, updates);
153
+ }
154
+ listAgentsByProject(projectId) {
155
+ return this.get(`/api/agents`, { project_id: projectId });
156
+ }
157
+ listProjects() {
158
+ return this.get("/api/projects");
159
+ }
160
+ registerProject(input) {
161
+ return this.post("/api/projects", input);
162
+ }
163
+ getProject(idOrName) {
164
+ return this.get(`/api/projects/${encodeURIComponent(idOrName)}`);
165
+ }
166
+ getProjectAgents(idOrName) {
167
+ return this.get(`/api/projects/${encodeURIComponent(idOrName)}/agents`);
168
+ }
169
+ listEntities(filter) {
170
+ return this.get("/api/entities", filter);
171
+ }
172
+ createEntity(input) {
173
+ return this.post("/api/entities", input);
174
+ }
175
+ mergeEntities(input) {
176
+ return this.post("/api/entities/merge", input);
177
+ }
178
+ getEntity(id) {
179
+ return this.get(`/api/entities/${id}`);
180
+ }
181
+ updateEntity(id, input) {
182
+ return this.patch(`/api/entities/${id}`, input);
183
+ }
184
+ deleteEntity(id) {
185
+ return this.delete(`/api/entities/${id}`);
186
+ }
187
+ getEntityMemories(entityId) {
188
+ return this.get(`/api/entities/${entityId}/memories`);
189
+ }
190
+ linkEntityMemory(entityId, input) {
191
+ return this.post(`/api/entities/${entityId}/memories`, input);
192
+ }
193
+ unlinkEntityMemory(entityId, memoryId) {
194
+ return this.delete(`/api/entities/${entityId}/memories/${memoryId}`);
195
+ }
196
+ getEntityRelations(entityId, filter) {
197
+ return this.get(`/api/entities/${entityId}/relations`, filter);
198
+ }
199
+ createRelation(input) {
200
+ return this.post("/api/relations", input);
201
+ }
202
+ getRelation(id) {
203
+ return this.get(`/api/relations/${id}`);
204
+ }
205
+ deleteRelation(id) {
206
+ return this.delete(`/api/relations/${id}`);
207
+ }
208
+ getGraph(entityId, options) {
209
+ const q = {};
210
+ if (options?.depth !== undefined)
211
+ q["depth"] = options.depth;
212
+ if (options?.relation_types?.length)
213
+ q["relation_types"] = options.relation_types.join(",");
214
+ return this.get(`/api/graph/${entityId}`, q);
215
+ }
216
+ findPath(fromId, toId) {
217
+ return this.get("/api/graph/path", { from: fromId, to: toId });
218
+ }
219
+ getGraphStats() {
220
+ return this.get("/api/graph/stats");
221
+ }
222
+ async acquireLock(input) {
223
+ try {
224
+ return await this.post("/api/locks", input);
225
+ } catch (e) {
226
+ if (e instanceof Error && e.message.includes("409"))
227
+ return null;
228
+ throw e;
229
+ }
230
+ }
231
+ checkLock(resourceType, resourceId, lockType) {
232
+ const params = { resource_type: resourceType, resource_id: resourceId };
233
+ if (lockType)
234
+ params["lock_type"] = lockType;
235
+ return this.get("/api/locks", params);
236
+ }
237
+ releaseLock(lockId, agentId) {
238
+ return this.request("DELETE", `/api/locks/${lockId}`, { agent_id: agentId });
239
+ }
240
+ listAgentLocks(agentId) {
241
+ return this.get(`/api/agents/${agentId}/locks`);
242
+ }
243
+ releaseAllAgentLocks(agentId) {
244
+ return this.request("DELETE", `/api/agents/${agentId}/locks`);
245
+ }
246
+ cleanExpiredLocks() {
247
+ return this.post("/api/locks/clean", {});
248
+ }
249
+ createTask(input) {
250
+ return this.post("/api/tasks", input);
251
+ }
252
+ listTasks(filter = {}) {
253
+ const q = {};
254
+ if (filter.status)
255
+ q["status"] = filter.status;
256
+ if (filter.priority)
257
+ q["priority"] = filter.priority;
258
+ if (filter.assigned_agent_id)
259
+ q["assigned_agent_id"] = filter.assigned_agent_id;
260
+ if (filter.project_id)
261
+ q["project_id"] = filter.project_id;
262
+ if (filter.session_id)
263
+ q["session_id"] = filter.session_id;
264
+ if (filter.parent_task_id !== undefined) {
265
+ q["parent_task_id"] = filter.parent_task_id ?? "null";
266
+ }
267
+ if (filter.tags?.length)
268
+ q["tags"] = filter.tags.join(",");
269
+ if (filter.limit !== undefined)
270
+ q["limit"] = filter.limit;
271
+ if (filter.offset !== undefined)
272
+ q["offset"] = filter.offset;
273
+ return this.get("/api/tasks", q);
274
+ }
275
+ getTaskStats(options) {
276
+ return this.get("/api/tasks/stats", options);
277
+ }
278
+ getTask(id) {
279
+ return this.get(`/api/tasks/${id}`);
280
+ }
281
+ updateTask(id, input) {
282
+ return this.patch(`/api/tasks/${id}`, input);
283
+ }
284
+ deleteTask(id) {
285
+ return this.delete(`/api/tasks/${id}`);
286
+ }
287
+ listTaskComments(taskId) {
288
+ return this.get(`/api/tasks/${taskId}/comments`);
289
+ }
290
+ addTaskComment(taskId, body, agentId) {
291
+ return this.post(`/api/tasks/${taskId}/comments`, { body, agent_id: agentId });
292
+ }
293
+ deleteTaskComment(taskId, commentId) {
294
+ return this.delete(`/api/tasks/${taskId}/comments/${commentId}`);
295
+ }
296
+ getContext(options) {
297
+ return this.get("/api/inject", options);
298
+ }
299
+ processConversationTurn(turn, context) {
300
+ return this.post("/api/auto-memory/process", { turn, ...context });
301
+ }
302
+ getAutoMemoryStatus() {
303
+ return this.get("/api/auto-memory/status");
304
+ }
305
+ configureAutoMemory(config) {
306
+ return this.request("PATCH", "/api/auto-memory/config", config);
307
+ }
308
+ testExtraction(turn, options) {
309
+ return this.post("/api/auto-memory/test", { turn, ...options });
310
+ }
311
+ listHooks(type) {
312
+ const params = type ? `?type=${encodeURIComponent(type)}` : "";
313
+ return this.get(`/api/hooks${params}`);
314
+ }
315
+ getHookStats() {
316
+ return this.get("/api/hooks/stats");
317
+ }
318
+ listWebhooks(filter) {
319
+ const params = new URLSearchParams;
320
+ if (filter?.type)
321
+ params.set("type", filter.type);
322
+ if (filter?.enabled !== undefined)
323
+ params.set("enabled", String(filter.enabled));
324
+ const qs = params.toString() ? `?${params.toString()}` : "";
325
+ return this.get(`/api/webhooks${qs}`);
326
+ }
327
+ createWebhook(input) {
328
+ return this.post("/api/webhooks", input);
329
+ }
330
+ getWebhook(id) {
331
+ return this.get(`/api/webhooks/${id}`);
332
+ }
333
+ updateWebhook(id, updates) {
334
+ return this.request("PATCH", `/api/webhooks/${id}`, updates);
335
+ }
336
+ deleteWebhook(id) {
337
+ return this.request("DELETE", `/api/webhooks/${id}`);
338
+ }
339
+ enableWebhook(id) {
340
+ return this.updateWebhook(id, { enabled: true });
341
+ }
342
+ disableWebhook(id) {
343
+ return this.updateWebhook(id, { enabled: false });
344
+ }
345
+ runSynthesis(options) {
346
+ return this.post("/api/synthesis/run", options ?? {});
347
+ }
348
+ listSynthesisRuns(filter) {
349
+ const params = new URLSearchParams;
350
+ if (filter?.project_id)
351
+ params.set("project_id", filter.project_id);
352
+ if (filter?.limit)
353
+ params.set("limit", String(filter.limit));
354
+ const qs = params.toString() ? `?${params.toString()}` : "";
355
+ return this.get(`/api/synthesis/runs${qs}`);
356
+ }
357
+ getSynthesisStatus(options) {
358
+ const params = new URLSearchParams;
359
+ if (options?.project_id)
360
+ params.set("project_id", options.project_id);
361
+ if (options?.run_id)
362
+ params.set("run_id", options.run_id);
363
+ const qs = params.toString() ? `?${params.toString()}` : "";
364
+ return this.get(`/api/synthesis/status${qs}`);
365
+ }
366
+ rollbackSynthesis(runId) {
367
+ return this.post(`/api/synthesis/rollback/${runId}`, {});
368
+ }
369
+ ingestSession(input) {
370
+ return this.post("/api/sessions/ingest", input);
371
+ }
372
+ getSessionJob(jobId) {
373
+ return this.get(`/api/sessions/jobs/${jobId}`);
374
+ }
375
+ listSessionJobs(filter) {
376
+ const params = new URLSearchParams;
377
+ if (filter?.agent_id)
378
+ params.set("agent_id", filter.agent_id);
379
+ if (filter?.project_id)
380
+ params.set("project_id", filter.project_id);
381
+ if (filter?.status)
382
+ params.set("status", filter.status);
383
+ if (filter?.limit)
384
+ params.set("limit", String(filter.limit));
385
+ const qs = params.toString() ? `?${params.toString()}` : "";
386
+ return this.get(`/api/sessions/jobs${qs}`);
387
+ }
388
+ getSessionQueueStats() {
389
+ return this.get("/api/sessions/queue/stats");
390
+ }
391
+ }
392
+ var sdk_default = MementosClient;
393
+ export {
394
+ sdk_default as default,
395
+ MementosError,
396
+ MementosClient
397
+ };