@illli-studio/mory 0.1.4 → 0.1.5

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/bundle/server.mjs CHANGED
@@ -77,7 +77,7 @@ const server = createServer(async (request, response) => { if (request.method ==
77
77
  if (request.method === "POST" && url.pathname === "/v1/memories") { const memory = makeMemory(await requestBody(request)); const duplicate = allMemories(memory.scope).find((item) => item.hash === memory.hash); if (duplicate) return send(response, 200, { memory: duplicate, duplicate: true }); insert(memory); addEvent("ADD", memory); linkEntities(memory); return send(response, 201, { memory, duplicate: false }); }
78
78
  const match = url.pathname.match(/^\/v1\/memories\/([^/]+)$/);
79
79
  if (match && request.method === "GET") { const memory = getMemory(match[1]); return memory ? send(response, 200, { memory }) : send(response, 404, { error: "memory not found" }); }
80
- if (match && request.method === "PATCH") { const current = getMemory(match[1]); if (!current) return send(response, 404, { error: "memory not found" }); db.prepare("DELETE FROM memory_fts WHERE memory_id = ?").run(current.id); db.prepare("DELETE FROM memories WHERE id = ?").run(current.id); const next = makeMemory({ ...current, ...await requestBody(request), id: current.id, sourceEventIds: [...current.sourceEventIds, current.id] }, current.source); insert(next); addEvent("UPDATE", next, { oldHash: current.hash, newHash: next.hash }); return send(response, 200, { memory: next }); }
80
+ if (match && request.method === "PATCH") { const current = getMemory(match[1]); if (!current) return send(response, 404, { error: "memory not found" }); const input = await requestBody(request); const nextText = String(input.text || input.content || input.payload?.content || current.text).trim(); const contentChanged = nextText !== current.text || String(input.title || current.title) !== current.title; const next = makeMemory({ ...current, ...input, id: current.id, text: nextText, hash: undefined, contentHash: undefined, embedding: contentChanged ? await embed(nextText) : current.embedding, sourceEventIds: [...current.sourceEventIds, randomUUID()] }, current.source); db.exec("BEGIN"); try { db.prepare("DELETE FROM memory_fts WHERE memory_id = ?").run(current.id); db.prepare("DELETE FROM memories WHERE id = ?").run(current.id); insert(next); addEvent("UPDATE", next, { oldHash: current.hash, newHash: next.hash }); db.exec("COMMIT"); } catch (error) { db.exec("ROLLBACK"); throw error; } return send(response, 200, { memory: next }); }
81
81
  if (match && request.method === "DELETE") { const memory = getMemory(match[1]); if (!memory) return send(response, 404, { error: "memory not found" }); db.prepare("UPDATE memories SET status = 'deleted', updated_at = ? WHERE id = ?").run(new Date().toISOString(), memory.id); db.prepare("DELETE FROM memory_fts WHERE memory_id = ?").run(memory.id); addEvent("DELETE", memory); return send(response, 200, { ok: true }); }
82
82
  if (request.method === "GET" && url.pathname === "/v1/export") return send(response, 200, { schemaVersion: 1, exportedAt: new Date().toISOString(), memories: allMemories({}) });
83
83
  if (request.method === "POST" && url.pathname === "/v1/import") { const input = await requestBody(request); if (!Array.isArray(input.memories)) return send(response, 400, { error: "memories array is required" }); const added = [], duplicates = []; for (const item of input.memories.slice(0, 10000)) { const memory = makeMemory(item); const duplicate = allMemories(memory.scope).find((candidate) => candidate.hash === memory.hash); if (duplicate) { duplicates.push(duplicate.id); continue; } if (getMemory(memory.id)) { duplicates.push(memory.id); continue; } insert(memory); addEvent("IMPORT", memory); linkEntities(memory); added.push(memory); } return send(response, 201, { addedCount: added.length, duplicateCount: duplicates.length, memories: added }); }
package/client/index.d.ts CHANGED
@@ -43,6 +43,10 @@ export declare class MoryClient {
43
43
  duplicateCount: number;
44
44
  }>;
45
45
  get(id: string): Promise<Record<string, unknown>>;
46
+ update(id: string, input: Partial<RememberInput> & {
47
+ title?: string;
48
+ tags?: string[];
49
+ }): Promise<Record<string, unknown>>;
46
50
  forget(id: string): Promise<{
47
51
  ok: boolean;
48
52
  }>;
package/client/index.js CHANGED
@@ -12,5 +12,6 @@ export class MoryClient {
12
12
  export() { return this.request("/v1/export", { method: "GET" }); }
13
13
  import(memories) { return this.request("/v1/import", { method: "POST", body: JSON.stringify({ memories }) }); }
14
14
  get(id) { return this.request(`/v1/memories/${encodeURIComponent(id)}`, { method: "GET" }); }
15
+ update(id, input) { return this.request(`/v1/memories/${encodeURIComponent(id)}`, { method: "PATCH", body: JSON.stringify(input) }); }
15
16
  forget(id) { return this.request(`/v1/memories/${encodeURIComponent(id)}`, { method: "DELETE" }); }
16
17
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@illli-studio/mory",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "Local-first memory runtime with a web console and MCP server.",
5
5
  "license": "AGPL-3.0-or-later",
6
6
  "publishConfig": { "access": "public" },
package/src/cli.mjs CHANGED
@@ -8,7 +8,7 @@ import { fileURLToPath } from "node:url";
8
8
  import { runMcp } from "./mcp.mjs";
9
9
 
10
10
  const packageRoot = resolve(fileURLToPath(new URL("..", import.meta.url)));
11
- const runtimeVersion = "0.1.4";
11
+ const runtimeVersion = "0.1.5";
12
12
  const repoRoot = resolve(packageRoot, "../..");
13
13
  const dataDir = process.env.MORY_HOME || join(homedir(), ".mory");
14
14
  const configPath = join(dataDir, "config.json");
package/src/mcp.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  const protocolVersion = "2025-06-18";
2
- const runtimeVersion = "0.1.4";
2
+ const runtimeVersion = "0.1.5";
3
3
 
4
4
  async function callApi(baseUrl, token, path, method = "POST", body) {
5
5
  const response = await fetch(baseUrl.replace(/\/$/, "") + path, { method, headers: { authorization: `Bearer ${token}`, "content-type": "application/json" }, body: body === undefined ? undefined : JSON.stringify(body) });
@@ -14,6 +14,7 @@ const tools = [
14
14
  { name: "mory_context", description: "Retrieve relevant memory as prompt-ready context.", inputSchema: { type: "object", properties: { query: { type: "string" }, projectId: { type: "string" }, limit: { type: "number" } }, required: ["query"] } },
15
15
  { name: "mory_get", description: "Get one local Mory memory by id.", inputSchema: { type: "object", properties: { memoryId: { type: "string" } }, required: ["memoryId"] } },
16
16
  { name: "mory_list", description: "List recent local Mory memories.", inputSchema: { type: "object", properties: { projectId: { type: "string" }, limit: { type: "number" } } } },
17
+ { name: "mory_update", description: "Update the content or metadata of an existing local Mory memory.", inputSchema: { type: "object", properties: { memoryId: { type: "string" }, text: { type: "string" }, title: { type: "string" }, kind: { type: "string" }, tags: { type: "array", items: { type: "string" } }, metadata: { type: "object" } }, required: ["memoryId"] } },
17
18
  { name: "mory_forget", description: "Delete a memory by id using Mory's tombstone deletion.", inputSchema: { type: "object", properties: { memoryId: { type: "string" } }, required: ["memoryId"] } }
18
19
  ];
19
20
 
@@ -29,6 +30,7 @@ async function handle(message, options) {
29
30
  else if (name === "mory_context") result = await callApi(options.baseUrl, options.token, "/v1/context", "POST", { query: input.query, limit: input.limit || 12, scope: input.projectId ? { projectId: input.projectId } : {} });
30
31
  else if (name === "mory_get") result = await callApi(options.baseUrl, options.token, `/v1/memories/${encodeURIComponent(input.memoryId)}`, "GET");
31
32
  else if (name === "mory_list") result = await callApi(options.baseUrl, options.token, `/v1/memories?limit=${encodeURIComponent(input.limit || 20)}${input.projectId ? `&projectId=${encodeURIComponent(input.projectId)}` : ""}`, "GET");
33
+ else if (name === "mory_update") result = await callApi(options.baseUrl, options.token, `/v1/memories/${encodeURIComponent(input.memoryId)}`, "PATCH", { text: input.text, title: input.title, kind: input.kind, tags: input.tags, metadata: input.metadata });
32
34
  else if (name === "mory_forget") result = await callApi(options.baseUrl, options.token, `/v1/memories/${encodeURIComponent(input.memoryId)}`, "DELETE");
33
35
  else throw new Error(`Unknown tool: ${name}`);
34
36
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };