From 241b2ddc79702b955af3aaebf71b7d859c4cf4bb Mon Sep 17 00:00:00 2001 From: jp Date: Sat, 11 Apr 2026 06:58:27 -0700 Subject: [PATCH 1/3] =?UTF-8?q?fix:=20standalone=20bug=20fixes=20=E2=80=94?= =?UTF-8?q?=20emotion=20regex,=20unicode=20checkmark,=20KG=20path,=20MCP?= =?UTF-8?q?=20args,=20spellcheck,=20init=20docs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove overly broad \*[^*]+\* from EMOTION_MARKERS (#536) - Replace Unicode checkmark with ASCII + for Windows cp1251/cp1252 (#535) - Fix spellcheck reading from wrong entity registry key (#570) - Add --yes flag to init instructions for non-interactive use (#534) - Default KG query direction to 'both' instead of 'outgoing' - Fix KG path mismatch in MCP server (#538) - Filter unexpected MCP tool args before dispatch (#572) Co-Authored-By: Claude Opus 4.6 --- mempalace/convo_miner.py | 2 +- mempalace/general_extractor.py | 1 - mempalace/instructions/init.md | 2 +- mempalace/knowledge_graph.py | 2 +- mempalace/mcp_server.py | 8 ++++---- mempalace/spellcheck.py | 4 ++-- mempalace/split_mega_files.py | 2 +- 7 files changed, 10 insertions(+), 11 deletions(-) diff --git a/mempalace/convo_miner.py b/mempalace/convo_miner.py index 3bb4a895bf..aca8f3a3a0 100644 --- a/mempalace/convo_miner.py +++ b/mempalace/convo_miner.py @@ -356,7 +356,7 @@ def mine_convos( raise total_drawers += drawers_added - print(f" ✓ [{i:4}/{len(files)}] {filepath.name[:50]:50} +{drawers_added}") + print(f" + [{i:4}/{len(files)}] {filepath.name[:50]:50} +{drawers_added}") print(f"\n{'=' * 55}") print(" Done.") diff --git a/mempalace/general_extractor.py b/mempalace/general_extractor.py index e849d7cf13..0a05cf46ca 100644 --- a/mempalace/general_extractor.py +++ b/mempalace/general_extractor.py @@ -157,7 +157,6 @@ r"i need", r"never told anyone", r"nobody knows", - r"\*[^*]+\*", ] ALL_MARKERS = { diff --git a/mempalace/instructions/init.md b/mempalace/instructions/init.md index 40fe8fcaaa..40f0c20dd7 100644 --- a/mempalace/instructions/init.md +++ b/mempalace/instructions/init.md @@ -41,7 +41,7 @@ before continuing. ## Step 5: Initialize the palace -Run `mempalace init ` where `` is the directory from Step 4. +Run `mempalace init --yes ` where `` is the directory from Step 4. If this fails, report the error and stop. diff --git a/mempalace/knowledge_graph.py b/mempalace/knowledge_graph.py index b094f06f7c..2199628823 100644 --- a/mempalace/knowledge_graph.py +++ b/mempalace/knowledge_graph.py @@ -193,7 +193,7 @@ def invalidate(self, subject: str, predicate: str, obj: str, ended: str = None): # ── Query operations ────────────────────────────────────────────────── - def query_entity(self, name: str, as_of: str = None, direction: str = "outgoing"): + def query_entity(self, name: str, as_of: str = None, direction: str = "both"): """ Get all relationships for an entity. diff --git a/mempalace/mcp_server.py b/mempalace/mcp_server.py index 09203b6b58..d30a530c6c 100644 --- a/mempalace/mcp_server.py +++ b/mempalace/mcp_server.py @@ -58,10 +58,7 @@ def _parse_args(): os.environ["MEMPALACE_PALACE_PATH"] = os.path.abspath(_args.palace) _config = MempalaceConfig() -if _args.palace: - _kg = KnowledgeGraph(db_path=os.path.join(_config.palace_path, "knowledge_graph.sqlite3")) -else: - _kg = KnowledgeGraph() +_kg = KnowledgeGraph(db_path=os.path.join(_config.palace_path, "knowledge_graph.sqlite3")) _client_cache = None @@ -984,6 +981,9 @@ def handle_request(request): tool_args[key] = int(value) elif declared_type == "number" and not isinstance(value, (int, float)): tool_args[key] = float(value) + # Strip unexpected kwargs — some MCP clients send extra params + # like top_k that the handler doesn't accept (#572). + tool_args = {k: v for k, v in tool_args.items() if k in schema_props} try: result = TOOLS[tool_name]["handler"](**tool_args) return { diff --git a/mempalace/spellcheck.py b/mempalace/spellcheck.py index fe8da38cdb..0368d33e8a 100644 --- a/mempalace/spellcheck.py +++ b/mempalace/spellcheck.py @@ -119,8 +119,8 @@ def _load_known_names() -> set: reg = EntityRegistry.load() names = set() - for entity in reg._data.get("entities", {}).values(): - names.add(entity.get("canonical", "").lower()) + for name, entity in reg._data.get("people", {}).items(): + names.add(name.lower()) for alias in entity.get("aliases", []): names.add(alias.lower()) return names diff --git a/mempalace/split_mega_files.py b/mempalace/split_mega_files.py index 24b59569c8..8552627a8e 100644 --- a/mempalace/split_mega_files.py +++ b/mempalace/split_mega_files.py @@ -224,7 +224,7 @@ def split_file(filepath, output_dir, dry_run=False): print(f" [{i + 1}/{len(boundaries) - 1}] {name} ({len(chunk)} lines)") else: out_path.write_text("".join(chunk), encoding="utf-8") - print(f" ✓ {name} ({len(chunk)} lines)") + print(f" + {name} ({len(chunk)} lines)") written.append(out_path) From d3d2bb462f1f2093e76e2e1415a004264422c443 Mon Sep 17 00:00:00 2001 From: jp Date: Sat, 11 Apr 2026 12:23:47 -0700 Subject: [PATCH 2/3] =?UTF-8?q?fix:=20allow=20Unicode=20in=20sanitize=5Fna?= =?UTF-8?q?me()=20=E2=80=94=20Latvian,=20CJK,=20Cyrillic=20names=20(#637)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit _SAFE_NAME_RE was ASCII-only, rejecting valid Unicode names. Changed to \w which matches Unicode letters/digits in Python 3. Co-Authored-By: Claude Opus 4.6 --- mempalace/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mempalace/config.py b/mempalace/config.py index fcfb2c8afe..91851b1112 100644 --- a/mempalace/config.py +++ b/mempalace/config.py @@ -16,7 +16,7 @@ # in file paths, SQLite, or ChromaDB metadata. MAX_NAME_LENGTH = 128 -_SAFE_NAME_RE = re.compile(r"^[a-zA-Z0-9][a-zA-Z0-9_ .'-]{0,126}[a-zA-Z0-9]?$") +_SAFE_NAME_RE = re.compile(r"^[\w][\w .'-]{0,126}[\w]?$") def sanitize_name(value: str, field_name: str = "name") -> str: From 52707ee5c7e4a2d451a06fb74b438fee49de4df8 Mon Sep 17 00:00:00 2001 From: jp Date: Sat, 11 Apr 2026 21:25:35 -0700 Subject: [PATCH 3/3] =?UTF-8?q?fix:=20restore=20conditional=20KG=20path=20?= =?UTF-8?q?=E2=80=94=20default=20differs=20from=20config.palace=5Fpath?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit KnowledgeGraph() uses its own default db_path which may differ from config.palace_path when --palace isn't specified. Only override when the user explicitly provides --palace. Per review feedback from bensig in #667. Co-Authored-By: Claude Opus 4.6 --- mempalace/mcp_server.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mempalace/mcp_server.py b/mempalace/mcp_server.py index d30a530c6c..2d46ae41c1 100644 --- a/mempalace/mcp_server.py +++ b/mempalace/mcp_server.py @@ -58,7 +58,10 @@ def _parse_args(): os.environ["MEMPALACE_PALACE_PATH"] = os.path.abspath(_args.palace) _config = MempalaceConfig() -_kg = KnowledgeGraph(db_path=os.path.join(_config.palace_path, "knowledge_graph.sqlite3")) +if _args.palace: + _kg = KnowledgeGraph(db_path=os.path.join(_config.palace_path, "knowledge_graph.sqlite3")) +else: + _kg = KnowledgeGraph() _client_cache = None