@sksoftofficial/mindroot 1.0.5 → 1.0.6

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sksoftofficial/mindroot",
3
- "version": "1.0.5",
3
+ "version": "1.0.6",
4
4
  "description": "Long-term memory for AI agents: hybrid-searched memories over human-editable markdown notes. 100% local — offline ONNX embeddings, SQLite FTS5, MCP server, REST API, CLI, dashboard. No cloud, no API keys.",
5
5
  "homepage": "https://skbilisim.com/en/projects/mindroot",
6
6
  "type": "module",
package/src/mcp.js CHANGED
@@ -4,12 +4,12 @@ const PROTOCOL_VERSION = "2025-06-18";
4
4
  export function tools() {
5
5
  return [
6
6
  {
7
- name: "mindroot_list_projects",
7
+ name: "list_projects",
8
8
  description: "List all projects known to mindroot with their note and memory counts. Use to discover valid project slugs before calling project-scoped tools.",
9
9
  inputSchema: { type: "object", properties: {} },
10
10
  },
11
11
  {
12
- name: "mindroot_search_projects",
12
+ name: "search_projects",
13
13
  description:
14
14
  "Find projects by fuzzy name. Matches project slugs semantically and by token overlap (e.g. 'mem-agent-mcp' finds 'proper-agent-memory'). Use to discover the right project slug before calling project-scoped tools.",
15
15
  inputSchema: {
@@ -19,7 +19,7 @@ export function tools() {
19
19
  },
20
20
  },
21
21
  {
22
- name: "mindroot_rename_project",
22
+ name: "rename_project",
23
23
  description:
24
24
  "Rename a project by slug. Moves its notes directory and updates the slug; notes, memories, and search indexes are preserved under the internal project id. The fuzzy-search vector for the new slug is rebuilt automatically on the next project search.",
25
25
  inputSchema: {
@@ -32,7 +32,7 @@ export function tools() {
32
32
  },
33
33
  },
34
34
  {
35
- name: "mindroot_search_memories",
35
+ name: "search_memories",
36
36
  description:
37
37
  "Search a project's memories — short, retrieval-optimized notes about durable facts, conventions, decisions, and gotchas. This is mindroot's primary semantic search layer (hybrid vector + keyword). Use before exploring a codebase or asking the user things that may already be remembered; mindroot_search_notes is only a literal string fallback. Hits include ids usable with mindroot_delete_memory.",
38
38
  inputSchema: {
@@ -46,7 +46,7 @@ export function tools() {
46
46
  },
47
47
  },
48
48
  {
49
- name: "mindroot_search_notes",
49
+ name: "search_notes",
50
50
  description:
51
51
  "Literal case-insensitive string search over a project's note sections — no semantics. Memories are the semantic index: prefer mindroot_search_memories first and use this only as a fallback or to locate exact keywords/identifiers inside notes. Returns the note path and heading section per hit; fetch just that section with mindroot_read_note's section argument.",
52
52
  inputSchema: {
@@ -60,7 +60,7 @@ export function tools() {
60
60
  },
61
61
  },
62
62
  {
63
- name: "mindroot_save_memory",
63
+ name: "save_memory",
64
64
  description:
65
65
  "Save a memory — a short, retrieval-optimized text about a durable fact, convention, decision, or gotcha for a project. Optionally link it to a note path ('notes/foo.md') or section ('notes/foo.md::Heading::Subheading'). Write memories so they answer 'when would someone need this'.",
66
66
  inputSchema: {
@@ -74,7 +74,7 @@ export function tools() {
74
74
  },
75
75
  },
76
76
  {
77
- name: "mindroot_delete_memory",
77
+ name: "delete_memory",
78
78
  description: "Delete a memory by id. Use to dedupe or remove stale entries. Ids come from mindroot_search_memories hits.",
79
79
  inputSchema: {
80
80
  type: "object",
@@ -83,7 +83,7 @@ export function tools() {
83
83
  },
84
84
  },
85
85
  {
86
- name: "mindroot_list_notes",
86
+ name: "list_notes",
87
87
  description:
88
88
  "List all memory notes for a project with their titles and section heading paths. Use this to see a note's section layout, then read only the section you need via mindroot_read_note's section argument instead of fetching the whole note.",
89
89
  inputSchema: {
@@ -93,7 +93,7 @@ export function tools() {
93
93
  },
94
94
  },
95
95
  {
96
- name: "mindroot_read_note",
96
+ name: "read_note",
97
97
  description:
98
98
  "Read a memory note. Without `section`, returns full content plus the section list. With `section` (a heading path like 'Architecture::Storage' from mindroot_list_notes or mindroot_search_notes targets), returns only that section's body — prefer this when you don't need the whole note. Verifies file integrity first and re-indexes automatically if the file was edited externally.",
99
99
  inputSchema: {
@@ -107,7 +107,7 @@ export function tools() {
107
107
  },
108
108
  },
109
109
  {
110
- name: "mindroot_save_note",
110
+ name: "save_note",
111
111
  description:
112
112
  "Create or fully overwrite a markdown memory note. Sections are parsed from headings (# .. ######) and are individually readable (mindroot_read_note `section`) and string-searchable (mindroot_search_notes); embeddings are generated for memories only. After saving, consider saving 1-3 linked memories (mindroot_save_memory with target_path) so key facts surface in memory searches.",
113
113
  inputSchema: {
@@ -121,7 +121,7 @@ export function tools() {
121
121
  },
122
122
  },
123
123
  {
124
- name: "mindroot_update_section",
124
+ name: "update_section",
125
125
  description:
126
126
  "Replace the body of an existing heading-section, or append it to the note when missing.",
127
127
  inputSchema: {
@@ -136,7 +136,7 @@ export function tools() {
136
136
  },
137
137
  },
138
138
  {
139
- name: "mindroot_delete_note",
139
+ name: "delete_note",
140
140
  description: "Delete a memory note and its sections index entries.",
141
141
  inputSchema: {
142
142
  type: "object",
@@ -150,29 +150,29 @@ export function tools() {
150
150
  async function callTool(db, name, args) {
151
151
  const core = await import("./core.js");
152
152
  switch (name) {
153
- case "mindroot_list_projects":
153
+ case "list_projects":
154
154
  return core.listProjects(db);
155
- case "mindroot_search_projects":
155
+ case "search_projects":
156
156
  return core.searchProjects(db, args.query);
157
- case "mindroot_rename_project":
157
+ case "rename_project":
158
158
  return core.renameProject(db, args.project, args.new_slug);
159
- case "mindroot_search_memories":
159
+ case "search_memories":
160
160
  return core.searchMemories(db, args.project, args.query, args.limit ?? 8);
161
- case "mindroot_search_notes":
161
+ case "search_notes":
162
162
  return core.searchNotes(db, args.project, args.query, args.limit ?? 8);
163
- case "mindroot_save_memory":
163
+ case "save_memory":
164
164
  return core.addMemory(db, args.project, args.text, args.target_path);
165
- case "mindroot_delete_memory":
165
+ case "delete_memory":
166
166
  return core.deleteMemory(db, args.project, Number(args.id));
167
- case "mindroot_list_notes":
167
+ case "list_notes":
168
168
  return core.listDocs(db, args.project);
169
- case "mindroot_read_note":
169
+ case "read_note":
170
170
  return core.readNote(db, args.project, args.path, args.section);
171
- case "mindroot_save_note":
171
+ case "save_note":
172
172
  return core.saveNote(db, args.project, args.path, args.content);
173
- case "mindroot_update_section":
173
+ case "update_section":
174
174
  return core.updateSection(db, args.project, args.path, args.heading_path, args.content);
175
- case "mindroot_delete_note":
175
+ case "delete_note":
176
176
  return core.deleteNote(db, args.project, args.path);
177
177
  default:
178
178
  throw new Error(`unknown tool: ${name}`);
package/test/mcp.test.js CHANGED
@@ -10,18 +10,18 @@ let db;
10
10
  let open;
11
11
 
12
12
  const EXPECTED_TOOLS = [
13
- "mindroot_list_projects",
14
- "mindroot_search_projects",
15
- "mindroot_rename_project",
16
- "mindroot_search_memories",
17
- "mindroot_search_notes",
18
- "mindroot_save_memory",
19
- "mindroot_delete_memory",
20
- "mindroot_list_notes",
21
- "mindroot_read_note",
22
- "mindroot_save_note",
23
- "mindroot_update_section",
24
- "mindroot_delete_note",
13
+ "list_projects",
14
+ "search_projects",
15
+ "rename_project",
16
+ "search_memories",
17
+ "search_notes",
18
+ "save_memory",
19
+ "delete_memory",
20
+ "list_notes",
21
+ "read_note",
22
+ "save_note",
23
+ "update_section",
24
+ "delete_note",
25
25
  ];
26
26
 
27
27
  before(async () => {
@@ -58,19 +58,19 @@ test("unknown tool returns clean error", async () => {
58
58
  });
59
59
 
60
60
  test("search without project is a clean isError", async () => {
61
- const res = await call("mindroot_search_memories", { query: "x" });
61
+ const res = await call("search_memories", { query: "x" });
62
62
  assert.equal(res.body.result.isError, true);
63
63
  assert.match(res.body.result.content[0].text, /project is required/);
64
64
  });
65
65
 
66
66
  test("invalid slug is rejected before any lookup", async () => {
67
- const res = await call("mindroot_search_memories", { project: "../evil", query: "x" });
67
+ const res = await call("search_memories", { project: "../evil", query: "x" });
68
68
  assert.equal(res.body.result.isError, true);
69
69
  assert.match(res.body.result.content[0].text, /invalid project slug/);
70
70
  });
71
71
 
72
72
  test("unknown project is a clean error", async () => {
73
- const res = await call("mindroot_search_memories", { project: "ghost", query: "x" });
73
+ const res = await call("search_memories", { project: "ghost", query: "x" });
74
74
  assert.match(res.body.result.content[0].text, /unknown project: ghost/);
75
75
  });
76
76
 
@@ -89,35 +89,35 @@ test("rename_project moves slug, dir, and embeddings", async () => {
89
89
  fs.mkdirSync(path.join(NOTES_DIR, "old-name"), { recursive: true });
90
90
  fs.writeFileSync(path.join(NOTES_DIR, "old-name", "overview.md"), "# Old\n");
91
91
 
92
- const res = await call("mindroot_rename_project", { project: "old-name", new_slug: "new-name" });
92
+ const res = await call("rename_project", { project: "old-name", new_slug: "new-name" });
93
93
  const data = JSON.parse(res.body.result.content[0].text);
94
94
  assert.deepEqual(data.renamed, { from: "old-name", to: "new-name" });
95
95
  assert.equal(db.prepare("SELECT slug FROM projects WHERE id = ?").get(pid).slug, "new-name");
96
96
  assert.ok(fs.existsSync(path.join(NOTES_DIR, "new-name", "overview.md")));
97
97
  assert.ok(!fs.existsSync(path.join(NOTES_DIR, "old-name")));
98
98
  assert.equal(db.prepare("SELECT COUNT(*) n FROM project_embeddings WHERE project_id = ?").get(pid).n, 0);
99
- const listed = JSON.parse((await call("mindroot_list_projects", {})).body.result.content[0].text);
99
+ const listed = JSON.parse((await call("list_projects", {})).body.result.content[0].text);
100
100
  const row = listed.find((p) => p.slug === "new-name");
101
101
  assert.equal(row.memories, 1);
102
102
  assert.ok(!listed.some((p) => p.slug === "old-name"));
103
103
 
104
- const dup = await call("mindroot_rename_project", { project: "new-name", new_slug: "new-name" });
104
+ const dup = await call("rename_project", { project: "new-name", new_slug: "new-name" });
105
105
  assert.equal(dup.body.result.isError, true);
106
106
  assert.match(dup.body.result.content[0].text, /already named/);
107
107
 
108
- const bad = await call("mindroot_rename_project", { project: "new-name", new_slug: "../evil" });
108
+ const bad = await call("rename_project", { project: "new-name", new_slug: "../evil" });
109
109
  assert.equal(bad.body.result.isError, true);
110
110
  assert.match(bad.body.result.content[0].text, /invalid project slug/);
111
111
  });
112
112
 
113
113
  test("update_section appends a missing section", async () => {
114
- await call("mindroot_save_note", {
114
+ await call("save_note", {
115
115
  project: "section-upsert",
116
116
  path: "note.md",
117
117
  content: "# Note\n\n## Existing\n\nkeep me\n",
118
118
  });
119
119
 
120
- const res = await call("mindroot_update_section", {
120
+ const res = await call("update_section", {
121
121
  project: "section-upsert",
122
122
  path: "note.md",
123
123
  heading_path: "Added",