Fix hash computation to exclude version/tags metadata

The publish dialog adds version and tags fields that aren't stored in
the local config.yaml. Exclude these from hash computation so the
hash comparison works correctly.

Also use Tool.to_dict() for consistent hash computation.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
rob 2026-01-16 08:02:42 -04:00
parent f1c462146b
commit 7f976d3f8c
2 changed files with 23 additions and 4 deletions

View File

@ -46,8 +46,14 @@ def get_tool_publish_state(tool_name: str) -> Tuple[str, Optional[str]]:
if not registry_hash:
return ("local", None)
# Compute current hash (excluding hash fields)
current_hash = compute_config_hash(config)
# Compute hash the same way as publish: load Tool object and use to_dict()
# This ensures we compare the same normalized representation
tool = load_tool(tool_name)
if tool:
current_hash = compute_config_hash(tool.to_dict())
else:
# Fallback to raw config if Tool can't be loaded
current_hash = compute_config_hash(config)
if current_hash != registry_hash:
return ("modified", registry_hash)
@ -473,15 +479,23 @@ class ToolsPage(QWidget):
# Get status from registry
status_data = client.get_my_tool_status(tool_name)
new_status = status_data.get("status", "pending")
new_hash = status_data.get("config_hash")
# Update local config
config_data = yaml.safe_load(config_path.read_text()) or {}
old_status = config_data.get("registry_status", "pending")
old_hash = config_data.get("registry_hash")
changed = False
if old_status != new_status:
config_data["registry_status"] = new_status
config_path.write_text(yaml.dump(config_data, default_flow_style=False, sort_keys=False))
changed = True
if new_hash and old_hash != new_hash:
config_data["registry_hash"] = new_hash
changed = True
if changed:
config_path.write_text(yaml.dump(config_data, default_flow_style=False, sort_keys=False))
self.refresh()
if new_status == "approved":
self.main_window.show_status(f"Tool '{tool_name}' has been approved!")

View File

@ -26,7 +26,12 @@ def compute_config_hash(config: Dict[str, Any], exclude_fields: Optional[list] =
Hash string in format "sha256:<64-char-hex>"
"""
if exclude_fields is None:
exclude_fields = ['published_hash', 'registry_hash']
# Exclude registry metadata and publication metadata from hash
# These fields are added during publish but aren't part of tool content
exclude_fields = [
'published_hash', 'registry_hash', 'registry_status', # registry metadata
'version', 'tags', # publication metadata (added by publish dialog)
]
# Create a copy without excluded fields
config_copy = {k: v for k, v in config.items() if k not in exclude_fields}