mirror of
https://github.com/basicmachines-co/basic-memory
synced 2026-06-21 13:47:35 +00:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 56c875f137 | |||
| 5049de7e2d | |||
| 49011768f7 | |||
| bc3557f000 | |||
| 611f5cd305 | |||
| 4ea392d284 | |||
| d491757980 |
@@ -20,6 +20,12 @@ You are an expert release manager for the Basic Memory project. When the user ru
|
||||
3. Verify we're on the `main` branch
|
||||
4. Confirm no existing tag with this version
|
||||
|
||||
#### Documentation Validation
|
||||
1. **Changelog Check**
|
||||
- CHANGELOG.md contains entry for target version
|
||||
- Entry includes all major features and fixes
|
||||
- Breaking changes are documented
|
||||
|
||||
### Step 2: Use Justfile Automation
|
||||
Execute the automated release process:
|
||||
```bash
|
||||
|
||||
@@ -1,5 +1,73 @@
|
||||
# CHANGELOG
|
||||
|
||||
## v0.13.5 (2025-06-11)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- **MCP Tools**: Renamed `create_project` tool to `create_memory_project` for namespace isolation
|
||||
- **Namespace**: Continued namespace isolation effort to prevent conflicts with other MCP servers
|
||||
|
||||
### Changes
|
||||
|
||||
- Tool functionality remains identical - only the name changed from `create_project` to `create_memory_project`
|
||||
- All integration tests updated to use the new tool name
|
||||
- Completes namespace isolation for project management tools alongside `list_memory_projects`
|
||||
|
||||
## v0.13.4 (2025-06-11)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- **MCP Tools**: Renamed `list_projects` tool to `list_memory_projects` to avoid naming conflicts with other MCP servers
|
||||
- **Namespace**: Improved tool naming specificity for better MCP server integration and isolation
|
||||
|
||||
### Changes
|
||||
|
||||
- Tool functionality remains identical - only the name changed from `list_projects` to `list_memory_projects`
|
||||
- All integration tests updated to use the new tool name
|
||||
- Better namespace isolation for Basic Memory MCP tools
|
||||
|
||||
## v0.13.3 (2025-06-11)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- **Projects**: Fixed case-insensitive project switching where switching succeeded but subsequent operations failed due to session state inconsistency
|
||||
- **Config**: Enhanced config manager with case-insensitive project lookup using permalink-based matching
|
||||
- **MCP Tools**: Updated project management tools to store canonical project names from database instead of user input
|
||||
- **API**: Improved project service to handle both name and permalink lookups consistently
|
||||
|
||||
### Technical Improvements
|
||||
|
||||
- Added comprehensive case-insensitive project switching test coverage with 5 new integration test scenarios
|
||||
- Fixed permalink generation inconsistencies where different case inputs could generate different permalinks
|
||||
- Enhanced project URL construction to use permalinks consistently across all API calls
|
||||
- Improved error handling and session state management for project operations
|
||||
|
||||
### Changes
|
||||
|
||||
- Project switching now preserves canonical project names from database in session state
|
||||
- All project operations use permalink-based lookups for case-insensitive matching
|
||||
- Enhanced test coverage ensures reliable case-insensitive project operations
|
||||
|
||||
## v0.13.2 (2025-06-11)
|
||||
|
||||
### Features
|
||||
|
||||
- **Release Management**: Added automated release management system with version control in `__init__.py`
|
||||
- **Automation**: Implemented justfile targets for `release` and `beta` commands with comprehensive quality gates
|
||||
- **CI/CD**: Enhanced release process with automatic version updates, git tagging, and GitHub release creation
|
||||
|
||||
### Development Experience
|
||||
|
||||
- Added `.claude/commands/release/` directory with automation documentation
|
||||
- Implemented release validation including lint, type-check, and test execution
|
||||
- Streamlined release workflow from manual process to single-command automation
|
||||
|
||||
### Technical Improvements
|
||||
|
||||
- Updated package version management to use actual version numbers instead of dynamic versioning
|
||||
- Added release process documentation and command references
|
||||
- Enhanced justfile with comprehensive release automation targets
|
||||
|
||||
## v0.13.1 (2025-06-11)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"""basic-memory - Local-first knowledge management combining Zettelkasten with knowledge graphs"""
|
||||
|
||||
# Package version - updated by release automation
|
||||
__version__ = "0.13.3"
|
||||
__version__ = "0.13.5"
|
||||
|
||||
# API version for FastAPI - independent of package version
|
||||
__api_version__ = "v0"
|
||||
|
||||
@@ -275,7 +275,7 @@ def get_project_config(project_name: Optional[str] = None) -> ProjectConfig:
|
||||
return ProjectConfig(name=name, home=Path(path))
|
||||
|
||||
# otherwise raise error
|
||||
raise ValueError(f"Project '{actual_project_name}' not found")
|
||||
raise ValueError(f"Project '{actual_project_name}' not found") # pragma: no cover
|
||||
|
||||
|
||||
# Create config manager
|
||||
|
||||
@@ -18,7 +18,7 @@ from basic_memory.schemas.project_info import ProjectList, ProjectStatusResponse
|
||||
from basic_memory.utils import generate_permalink
|
||||
|
||||
|
||||
@mcp.tool()
|
||||
@mcp.tool("list_memory_projects")
|
||||
async def list_projects(ctx: Context | None = None) -> str:
|
||||
"""List all available projects with their status.
|
||||
|
||||
@@ -230,7 +230,7 @@ async def set_default_project(project_name: str, ctx: Context | None = None) ->
|
||||
return add_project_metadata(result, session.get_current_project())
|
||||
|
||||
|
||||
@mcp.tool()
|
||||
@mcp.tool("create_memory_project")
|
||||
async def create_project(
|
||||
project_name: str, project_path: str, set_default: bool = False, ctx: Context | None = None
|
||||
) -> str:
|
||||
|
||||
@@ -15,7 +15,7 @@ async def test_list_projects_basic_operation(mcp_server, app):
|
||||
async with Client(mcp_server) as client:
|
||||
# List all available projects
|
||||
list_result = await client.call_tool(
|
||||
"list_projects",
|
||||
"list_memory_projects",
|
||||
{},
|
||||
)
|
||||
|
||||
@@ -248,7 +248,7 @@ async def test_project_management_workflow(mcp_server, app):
|
||||
assert "test-project" in current_result[0].text
|
||||
|
||||
# 2. List all projects
|
||||
list_result = await client.call_tool("list_projects", {})
|
||||
list_result = await client.call_tool("list_memory_projects", {})
|
||||
assert "Available projects:" in list_result[0].text
|
||||
assert "test-project" in list_result[0].text
|
||||
|
||||
@@ -269,7 +269,7 @@ async def test_project_metadata_consistency(mcp_server, app):
|
||||
# Test all project management tools and verify they include project metadata
|
||||
|
||||
# list_projects
|
||||
list_result = await client.call_tool("list_projects", {})
|
||||
list_result = await client.call_tool("list_memory_projects", {})
|
||||
assert "Project: test-project" in list_result[0].text
|
||||
|
||||
# get_current_project
|
||||
@@ -350,7 +350,7 @@ async def test_create_project_basic_operation(mcp_server, app):
|
||||
async with Client(mcp_server) as client:
|
||||
# Create a new project
|
||||
create_result = await client.call_tool(
|
||||
"create_project",
|
||||
"create_memory_project",
|
||||
{
|
||||
"project_name": "test-new-project",
|
||||
"project_path": "/tmp/test-new-project",
|
||||
@@ -370,7 +370,7 @@ async def test_create_project_basic_operation(mcp_server, app):
|
||||
assert "Project: test-project" in create_text # Should still show current project
|
||||
|
||||
# Verify project appears in project list
|
||||
list_result = await client.call_tool("list_projects", {})
|
||||
list_result = await client.call_tool("list_memory_projects", {})
|
||||
list_text = list_result[0].text
|
||||
assert "test-new-project" in list_text
|
||||
|
||||
@@ -382,7 +382,7 @@ async def test_create_project_with_default_flag(mcp_server, app):
|
||||
async with Client(mcp_server) as client:
|
||||
# Create a new project and set as default
|
||||
create_result = await client.call_tool(
|
||||
"create_project",
|
||||
"create_memory_project",
|
||||
{
|
||||
"project_name": "test-default-project",
|
||||
"project_path": "/tmp/test-default-project",
|
||||
@@ -412,7 +412,7 @@ async def test_create_project_duplicate_name(mcp_server, app):
|
||||
async with Client(mcp_server) as client:
|
||||
# First create a project
|
||||
await client.call_tool(
|
||||
"create_project",
|
||||
"create_memory_project",
|
||||
{
|
||||
"project_name": "duplicate-test",
|
||||
"project_path": "/tmp/duplicate-test-1",
|
||||
@@ -422,7 +422,7 @@ async def test_create_project_duplicate_name(mcp_server, app):
|
||||
# Try to create another project with same name
|
||||
with pytest.raises(Exception) as exc_info:
|
||||
await client.call_tool(
|
||||
"create_project",
|
||||
"create_memory_project",
|
||||
{
|
||||
"project_name": "duplicate-test",
|
||||
"project_path": "/tmp/duplicate-test-2",
|
||||
@@ -431,7 +431,7 @@ async def test_create_project_duplicate_name(mcp_server, app):
|
||||
|
||||
# Should show error about duplicate name
|
||||
error_message = str(exc_info.value)
|
||||
assert "create_project" in error_message
|
||||
assert "create_memory_project" in error_message
|
||||
assert (
|
||||
"duplicate-test" in error_message
|
||||
or "already exists" in error_message
|
||||
@@ -446,7 +446,7 @@ async def test_delete_project_basic_operation(mcp_server, app):
|
||||
async with Client(mcp_server) as client:
|
||||
# First create a project to delete
|
||||
await client.call_tool(
|
||||
"create_project",
|
||||
"create_memory_project",
|
||||
{
|
||||
"project_name": "to-be-deleted",
|
||||
"project_path": "/tmp/to-be-deleted",
|
||||
@@ -454,7 +454,7 @@ async def test_delete_project_basic_operation(mcp_server, app):
|
||||
)
|
||||
|
||||
# Verify it exists
|
||||
list_result = await client.call_tool("list_projects", {})
|
||||
list_result = await client.call_tool("list_memory_projects", {})
|
||||
assert "to-be-deleted" in list_result[0].text
|
||||
|
||||
# Delete the project
|
||||
@@ -478,7 +478,7 @@ async def test_delete_project_basic_operation(mcp_server, app):
|
||||
assert "Project: test-project" in delete_text # Should show current project
|
||||
|
||||
# Verify project no longer appears in list
|
||||
list_result_after = await client.call_tool("list_projects", {})
|
||||
list_result_after = await client.call_tool("list_memory_projects", {})
|
||||
assert "to-be-deleted" not in list_result_after[0].text
|
||||
|
||||
|
||||
@@ -540,7 +540,7 @@ async def test_project_lifecycle_workflow(mcp_server, app):
|
||||
|
||||
# 1. Create new project
|
||||
create_result = await client.call_tool(
|
||||
"create_project",
|
||||
"create_memory_project",
|
||||
{
|
||||
"project_name": project_name,
|
||||
"project_path": project_path,
|
||||
@@ -595,7 +595,7 @@ async def test_project_lifecycle_workflow(mcp_server, app):
|
||||
assert "removed successfully" in delete_result[0].text
|
||||
|
||||
# 7. Verify project is gone from list
|
||||
list_result = await client.call_tool("list_projects", {})
|
||||
list_result = await client.call_tool("list_memory_projects", {})
|
||||
assert project_name not in list_result[0].text
|
||||
|
||||
|
||||
@@ -609,7 +609,7 @@ async def test_create_delete_project_edge_cases(mcp_server, app):
|
||||
|
||||
# Create project with special characters
|
||||
create_result = await client.call_tool(
|
||||
"create_project",
|
||||
"create_memory_project",
|
||||
{
|
||||
"project_name": special_name,
|
||||
"project_path": f"/tmp/{special_name}",
|
||||
@@ -619,7 +619,7 @@ async def test_create_delete_project_edge_cases(mcp_server, app):
|
||||
assert special_name in create_result[0].text
|
||||
|
||||
# Verify it appears in list
|
||||
list_result = await client.call_tool("list_projects", {})
|
||||
list_result = await client.call_tool("list_memory_projects", {})
|
||||
assert special_name in list_result[0].text
|
||||
|
||||
# Delete it
|
||||
@@ -633,7 +633,7 @@ async def test_create_delete_project_edge_cases(mcp_server, app):
|
||||
assert special_name in delete_result[0].text
|
||||
|
||||
# Verify it's gone
|
||||
list_result_after = await client.call_tool("list_projects", {})
|
||||
list_result_after = await client.call_tool("list_memory_projects", {})
|
||||
assert special_name not in list_result_after[0].text
|
||||
|
||||
|
||||
@@ -645,7 +645,7 @@ async def test_case_insensitive_project_switching(mcp_server, app):
|
||||
# Create a project with mixed case name
|
||||
project_name = "Personal-Project"
|
||||
create_result = await client.call_tool(
|
||||
"create_project",
|
||||
"create_memory_project",
|
||||
{
|
||||
"project_name": project_name,
|
||||
"project_path": f"/tmp/{project_name}",
|
||||
@@ -655,7 +655,7 @@ async def test_case_insensitive_project_switching(mcp_server, app):
|
||||
assert project_name in create_result[0].text
|
||||
|
||||
# Verify project was created with canonical name
|
||||
list_result = await client.call_tool("list_projects", {})
|
||||
list_result = await client.call_tool("list_memory_projects", {})
|
||||
assert project_name in list_result[0].text
|
||||
|
||||
# Test switching with different case variations
|
||||
@@ -709,7 +709,7 @@ async def test_case_insensitive_project_operations(mcp_server, app):
|
||||
# Create a project with capital letters
|
||||
project_name = "CamelCase-Project"
|
||||
create_result = await client.call_tool(
|
||||
"create_project",
|
||||
"create_memory_project",
|
||||
{
|
||||
"project_name": project_name,
|
||||
"project_path": f"/tmp/{project_name}",
|
||||
@@ -809,7 +809,7 @@ async def test_case_preservation_in_project_list(mcp_server, app):
|
||||
# Create all test projects
|
||||
for project_name in test_projects:
|
||||
await client.call_tool(
|
||||
"create_project",
|
||||
"create_memory_project",
|
||||
{
|
||||
"project_name": project_name,
|
||||
"project_path": f"/tmp/{project_name}",
|
||||
@@ -817,7 +817,7 @@ async def test_case_preservation_in_project_list(mcp_server, app):
|
||||
)
|
||||
|
||||
# List projects and verify each appears with its original case
|
||||
list_result = await client.call_tool("list_projects", {})
|
||||
list_result = await client.call_tool("list_memory_projects", {})
|
||||
list_text = list_result[0].text
|
||||
|
||||
for project_name in test_projects:
|
||||
@@ -854,7 +854,7 @@ async def test_session_state_consistency_after_case_switch(mcp_server, app):
|
||||
# Create a project with specific case
|
||||
project_name = "Session-Test-Project"
|
||||
await client.call_tool(
|
||||
"create_project",
|
||||
"create_memory_project",
|
||||
{
|
||||
"project_name": project_name,
|
||||
"project_path": f"/tmp/{project_name}",
|
||||
@@ -880,7 +880,7 @@ async def test_session_state_consistency_after_case_switch(mcp_server, app):
|
||||
),
|
||||
("get_current_project", {}),
|
||||
("search_notes", {"query": "session"}),
|
||||
("list_projects", {}),
|
||||
("list_memory_projects", {}),
|
||||
]
|
||||
|
||||
for op_name, op_params in operations:
|
||||
@@ -889,7 +889,7 @@ async def test_session_state_consistency_after_case_switch(mcp_server, app):
|
||||
# All operations should work and reference the canonical project name
|
||||
if op_name == "get_current_project":
|
||||
assert f"Current project: {project_name}" in result[0].text
|
||||
elif op_name == "list_projects":
|
||||
elif op_name == "list_memory_projects":
|
||||
assert project_name in result[0].text
|
||||
assert "(current)" in result[0].text or "current" in result[0].text.lower()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user