basic-memory 0.2.20__tar.gz → 0.3.0__tar.gz
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.
Potentially problematic release.
This version of basic-memory might be problematic. Click here for more details.
- {basic_memory-0.2.20 → basic_memory-0.3.0}/.github/workflows/release.yml +13 -35
- {basic_memory-0.2.20 → basic_memory-0.3.0}/.gitignore +1 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/CHANGELOG.md +27 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/Makefile +1 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/PKG-INFO +1 -1
- basic_memory-0.3.0/installer/README.md +26 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/installer/installer.py +1 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/installer/setup.py +11 -13
- {basic_memory-0.2.20 → basic_memory-0.3.0}/pyproject.toml +4 -2
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/__init__.py +1 -1
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/api/app.py +3 -24
- basic_memory-0.3.0/src/basic_memory/cli/app.py +13 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/cli/commands/db.py +1 -1
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/cli/commands/mcp.py +2 -2
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/cli/commands/status.py +5 -7
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/cli/commands/sync.py +44 -44
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/db.py +21 -28
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/mcp/async_client.py +1 -1
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/mcp/tools/notes.py +4 -1
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/sync/utils.py +1 -4
- {basic_memory-0.2.20 → basic_memory-0.3.0}/tests/conftest.py +2 -5
- {basic_memory-0.2.20 → basic_memory-0.3.0}/tests/mcp/test_tool_notes.py +22 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/uv.lock +1 -1
- basic_memory-0.2.20/installer/README.md +0 -16
- basic_memory-0.2.20/src/basic_memory/cli/app.py +0 -3
- {basic_memory-0.2.20 → basic_memory-0.3.0}/.github/workflows/pr-title.yml +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/.github/workflows/test.yml +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/.python-version +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/CITATION.cff +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/CODE_OF_CONDUCT.md +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/CONTRIBUTING.md +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/LICENSE +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/README.md +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/alembic.ini +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/basic-memory.md +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/installer/Basic.icns +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/installer/icon.svg +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/installer/make_icons.sh +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/memory.json +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/scripts/install.sh +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/alembic/README +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/alembic/env.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/alembic/migrations.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/alembic/script.py.mako +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/alembic/versions/3dae7c7b1564_initial_schema.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/api/__init__.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/api/routers/__init__.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/api/routers/knowledge_router.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/api/routers/memory_router.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/api/routers/resource_router.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/api/routers/search_router.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/cli/__init__.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/cli/commands/__init__.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/cli/commands/import_memory_json.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/cli/main.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/config.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/deps.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/file_utils.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/markdown/__init__.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/markdown/entity_parser.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/markdown/markdown_processor.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/markdown/plugins.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/markdown/schemas.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/markdown/utils.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/mcp/__init__.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/mcp/server.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/mcp/tools/__init__.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/mcp/tools/knowledge.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/mcp/tools/memory.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/mcp/tools/search.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/mcp/tools/utils.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/models/__init__.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/models/base.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/models/knowledge.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/models/search.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/repository/__init__.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/repository/entity_repository.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/repository/observation_repository.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/repository/relation_repository.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/repository/repository.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/repository/search_repository.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/schemas/__init__.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/schemas/base.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/schemas/delete.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/schemas/discovery.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/schemas/memory.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/schemas/request.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/schemas/response.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/schemas/search.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/services/__init__.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/services/context_service.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/services/entity_service.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/services/exceptions.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/services/file_service.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/services/link_resolver.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/services/search_service.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/services/service.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/sync/__init__.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/sync/file_change_scanner.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/sync/sync_service.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/sync/watch_service.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/utils.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/tests/api/conftest.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/tests/api/test_knowledge_router.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/tests/api/test_memory_router.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/tests/api/test_resource_router.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/tests/api/test_search_router.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/tests/cli/test_import_memory_json.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/tests/cli/test_status.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/tests/cli/test_sync.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/tests/edit_file_test.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/tests/markdown/__init__.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/tests/markdown/test_entity_parser.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/tests/markdown/test_markdown_plugins.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/tests/markdown/test_markdown_processor.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/tests/markdown/test_observation_edge_cases.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/tests/markdown/test_parser_edge_cases.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/tests/markdown/test_relation_edge_cases.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/tests/markdown/test_task_detection.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/tests/mcp/conftest.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/tests/mcp/test_tool_get_entity.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/tests/mcp/test_tool_knowledge.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/tests/mcp/test_tool_memory.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/tests/mcp/test_tool_search.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/tests/mcp/test_tool_utils.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/tests/repository/test_entity_repository.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/tests/repository/test_observation_repository.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/tests/repository/test_relation_repository.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/tests/repository/test_repository.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/tests/schemas/test_memory_url.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/tests/schemas/test_schemas.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/tests/schemas/test_search.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/tests/services/test_context_service.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/tests/services/test_entity_service.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/tests/services/test_file_service.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/tests/services/test_link_resolver.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/tests/services/test_search_service.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/tests/sync/test_file_change_scanner.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/tests/sync/test_sync_service.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/tests/sync/test_watch_service.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/tests/test_basic_memory.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/tests/utils/test_file_utils.py +0 -0
- {basic_memory-0.2.20 → basic_memory-0.3.0}/tests/utils/test_permalink_formatting.py +0 -0
|
@@ -57,10 +57,14 @@ jobs:
|
|
|
57
57
|
with:
|
|
58
58
|
ref: ${{ needs.release.outputs.tag }}
|
|
59
59
|
|
|
60
|
-
- name: Set up Python
|
|
61
|
-
uses: actions/setup-python@
|
|
60
|
+
- name: Set up Python "3.12"
|
|
61
|
+
uses: actions/setup-python@v4
|
|
62
62
|
with:
|
|
63
|
-
python-version:
|
|
63
|
+
python-version: "3.12"
|
|
64
|
+
cache: 'pip'
|
|
65
|
+
|
|
66
|
+
- name: Install librsvg
|
|
67
|
+
run: brew install librsvg
|
|
64
68
|
|
|
65
69
|
- name: Install uv
|
|
66
70
|
run: |
|
|
@@ -72,47 +76,21 @@ jobs:
|
|
|
72
76
|
|
|
73
77
|
- name: Install dependencies
|
|
74
78
|
run: |
|
|
75
|
-
uv
|
|
76
|
-
|
|
77
|
-
- name: Install librsvg
|
|
78
|
-
run: brew install librsvg
|
|
79
|
-
|
|
80
|
-
- name: Create icon
|
|
81
|
-
run: |
|
|
82
|
-
cd installer
|
|
83
|
-
chmod +x make_icons.sh
|
|
84
|
-
./make_icons.sh
|
|
79
|
+
uv sync
|
|
85
80
|
|
|
86
81
|
- name: Build macOS installer
|
|
87
82
|
run: |
|
|
88
|
-
# Debug info
|
|
89
|
-
echo "Environment Info:"
|
|
90
|
-
uv pip list
|
|
91
|
-
python --version
|
|
92
|
-
which uv
|
|
93
|
-
which python
|
|
94
|
-
ls -la $(dirname $(which python))
|
|
95
|
-
echo "PYTHONPATH=$PYTHONPATH"
|
|
96
|
-
|
|
97
|
-
# Build
|
|
98
83
|
make installer-mac
|
|
99
|
-
|
|
84
|
+
xattr -dr com.apple.quarantine "installer/build/Basic Memory Installer.app"
|
|
100
85
|
|
|
101
|
-
- name:
|
|
86
|
+
- name: Zip macOS installer
|
|
102
87
|
run: |
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
# - name: Zip macOS installer
|
|
108
|
-
# run: |
|
|
109
|
-
# cd installer/build
|
|
110
|
-
# zip -ry "Basic-Memory-Installer-${{ needs.release.outputs.tag }}.zip" "Basic Memory Installer.app"
|
|
88
|
+
cd installer/build
|
|
89
|
+
zip -ry "Basic-Memory-Installer-${{ needs.release.outputs.tag }}.zip" "Basic Memory Installer.app"
|
|
111
90
|
|
|
112
91
|
- name: Upload macOS installer
|
|
113
92
|
uses: softprops/action-gh-release@v1
|
|
114
93
|
with:
|
|
115
|
-
|
|
116
|
-
files: installer/build/*
|
|
94
|
+
files: installer/build/Basic-Memory-Installer-${{ needs.release.outputs.tag }}.zip
|
|
117
95
|
tag_name: ${{ needs.release.outputs.tag }}
|
|
118
96
|
token: ${{ secrets.GITHUB_TOKEN }}
|
|
@@ -1,6 +1,33 @@
|
|
|
1
1
|
# CHANGELOG
|
|
2
2
|
|
|
3
3
|
|
|
4
|
+
## v0.3.0 (2025-02-15)
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
- Refactor db schema migrate handling
|
|
9
|
+
([`ca632be`](https://github.com/basicmachines-co/basic-memory/commit/ca632beb6fed5881f4d8ba5ce698bb5bc681e6aa))
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
## v0.2.21 (2025-02-15)
|
|
13
|
+
|
|
14
|
+
### Bug Fixes
|
|
15
|
+
|
|
16
|
+
- Fix osx installer github action
|
|
17
|
+
([`65ebe5d`](https://github.com/basicmachines-co/basic-memory/commit/65ebe5d19491e5ff047c459d799498ad5dd9cd1a))
|
|
18
|
+
|
|
19
|
+
- Handle memory:// url format in read_note tool
|
|
20
|
+
([`e080373`](https://github.com/basicmachines-co/basic-memory/commit/e0803734e69eeb6c6d7432eea323c7a264cb8347))
|
|
21
|
+
|
|
22
|
+
- Remove create schema from init_db
|
|
23
|
+
([`674dd1f`](https://github.com/basicmachines-co/basic-memory/commit/674dd1fd47be9e60ac17508476c62254991df288))
|
|
24
|
+
|
|
25
|
+
### Features
|
|
26
|
+
|
|
27
|
+
- Set version in var, output version at startup
|
|
28
|
+
([`a91da13`](https://github.com/basicmachines-co/basic-memory/commit/a91da1396710e62587df1284da00137d156fc05e))
|
|
29
|
+
|
|
30
|
+
|
|
4
31
|
## v0.2.20 (2025-02-14)
|
|
5
32
|
|
|
6
33
|
### Bug Fixes
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: basic-memory
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Local-first knowledge management combining Zettelkasten with knowledge graphs
|
|
5
5
|
Project-URL: Homepage, https://github.com/basicmachines-co/basic-memory
|
|
6
6
|
Project-URL: Repository, https://github.com/basicmachines-co/basic-memory
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Basic Memory Installer
|
|
2
|
+
|
|
3
|
+
This installer configures Basic Memory to work with Claude Desktop.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
1. Download the latest installer from the [releases page](https://github.com/basicmachines-co/basic-memory/releases)
|
|
8
|
+
2. Unzip the downloaded file
|
|
9
|
+
3. Since the app is currently unsigned, you'll need to:
|
|
10
|
+
|
|
11
|
+
On your Mac, choose Apple menu > System Settings, then click Privacy & Security in the sidebar. (You may need to
|
|
12
|
+
scroll down.)
|
|
13
|
+
|
|
14
|
+
Go to Security, then click Open.
|
|
15
|
+
|
|
16
|
+
Click Open Anyway.
|
|
17
|
+
|
|
18
|
+
This button is available for about an hour after you try to open the app.
|
|
19
|
+
|
|
20
|
+
Enter your login password, then click OK.
|
|
21
|
+
|
|
22
|
+
https://support.apple.com/guide/mac-help/apple-cant-check-app-for-malicious-software-mchleab3a043/mac
|
|
23
|
+
|
|
24
|
+
5. Restart Claude Desktop
|
|
25
|
+
|
|
26
|
+
The warning only appears the first time you open the app. Future updates will include proper code signing.
|
|
@@ -4,27 +4,24 @@ import sys
|
|
|
4
4
|
# Build options for all platforms
|
|
5
5
|
build_exe_options = {
|
|
6
6
|
"packages": ["json", "pathlib"],
|
|
7
|
-
"excludes": [],
|
|
7
|
+
"excludes": ["unittest", "pydoc", "test"],
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
# Platform-specific options
|
|
11
11
|
if sys.platform == "win32":
|
|
12
12
|
base = "Win32GUI" # Use GUI base for Windows
|
|
13
|
-
build_exe_options.update(
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
build_exe_options.update(
|
|
14
|
+
{
|
|
15
|
+
"include_msvcr": True,
|
|
16
|
+
}
|
|
17
|
+
)
|
|
16
18
|
target_name = "Basic Memory Installer.exe"
|
|
17
19
|
else: # darwin
|
|
18
20
|
base = None # Don't use GUI base for macOS
|
|
19
21
|
target_name = "Basic Memory Installer"
|
|
20
22
|
|
|
21
23
|
executables = [
|
|
22
|
-
Executable(
|
|
23
|
-
script="installer.py",
|
|
24
|
-
target_name=target_name,
|
|
25
|
-
base=base,
|
|
26
|
-
icon="Basic.icns"
|
|
27
|
-
)
|
|
24
|
+
Executable(script="installer.py", target_name=target_name, base=base, icon="Basic.icns")
|
|
28
25
|
]
|
|
29
26
|
|
|
30
27
|
setup(
|
|
@@ -35,8 +32,9 @@ setup(
|
|
|
35
32
|
"build_exe": build_exe_options,
|
|
36
33
|
"bdist_mac": {
|
|
37
34
|
"bundle_name": "Basic Memory Installer",
|
|
38
|
-
"iconfile": "Basic.icns"
|
|
39
|
-
|
|
35
|
+
"iconfile": "Basic.icns",
|
|
36
|
+
"codesign_identity": "-", # Force ad-hoc signing
|
|
37
|
+
},
|
|
40
38
|
},
|
|
41
39
|
executables=executables,
|
|
42
|
-
)
|
|
40
|
+
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "basic-memory"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.3.0"
|
|
4
4
|
description = "Local-first knowledge management combining Zettelkasten with knowledge graphs"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.12.1"
|
|
@@ -84,7 +84,9 @@ pythonVersion = "3.12"
|
|
|
84
84
|
|
|
85
85
|
|
|
86
86
|
[tool.semantic_release]
|
|
87
|
-
|
|
87
|
+
version_variables = [
|
|
88
|
+
"src/basic_memory/__init__.py:__version__",
|
|
89
|
+
]
|
|
88
90
|
version_toml = [
|
|
89
91
|
"pyproject.toml:project.version",
|
|
90
92
|
]
|
|
@@ -6,38 +6,17 @@ from fastapi import FastAPI, HTTPException
|
|
|
6
6
|
from fastapi.exception_handlers import http_exception_handler
|
|
7
7
|
from loguru import logger
|
|
8
8
|
|
|
9
|
+
import basic_memory
|
|
9
10
|
from basic_memory import db
|
|
10
11
|
from basic_memory.config import config as app_config
|
|
11
12
|
from basic_memory.api.routers import knowledge, search, memory, resource
|
|
12
|
-
from alembic import command
|
|
13
|
-
from alembic.config import Config
|
|
14
|
-
|
|
15
|
-
from basic_memory.db import DatabaseType
|
|
16
|
-
from basic_memory.repository.search_repository import SearchRepository
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
async def run_migrations(): # pragma: no cover
|
|
20
|
-
"""Run any pending alembic migrations."""
|
|
21
|
-
logger.info("Running database migrations...")
|
|
22
|
-
try:
|
|
23
|
-
config = Config("alembic.ini")
|
|
24
|
-
command.upgrade(config, "head")
|
|
25
|
-
logger.info("Migrations completed successfully")
|
|
26
|
-
|
|
27
|
-
_, session_maker = await db.get_or_create_db(
|
|
28
|
-
app_config.database_path, DatabaseType.FILESYSTEM
|
|
29
|
-
)
|
|
30
|
-
await SearchRepository(session_maker).init_search_index()
|
|
31
|
-
except Exception as e:
|
|
32
|
-
logger.error(f"Error running migrations: {e}")
|
|
33
|
-
raise
|
|
34
13
|
|
|
35
14
|
|
|
36
15
|
@asynccontextmanager
|
|
37
16
|
async def lifespan(app: FastAPI): # pragma: no cover
|
|
38
17
|
"""Lifecycle manager for the FastAPI app."""
|
|
39
|
-
logger.info("Starting Basic Memory API")
|
|
40
|
-
await run_migrations()
|
|
18
|
+
logger.info(f"Starting Basic Memory API {basic_memory.__version__}")
|
|
19
|
+
await db.run_migrations(app_config)
|
|
41
20
|
yield
|
|
42
21
|
logger.info("Shutting down Basic Memory API")
|
|
43
22
|
await db.shutdown_db()
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
|
|
3
|
+
import typer
|
|
4
|
+
|
|
5
|
+
from basic_memory import db
|
|
6
|
+
from basic_memory.config import config
|
|
7
|
+
from basic_memory.utils import setup_logging
|
|
8
|
+
|
|
9
|
+
setup_logging(log_file=".basic-memory/basic-memory-cli.log") # pragma: no cover
|
|
10
|
+
|
|
11
|
+
asyncio.run(db.run_migrations(config))
|
|
12
|
+
|
|
13
|
+
app = typer.Typer()
|
|
@@ -12,9 +12,9 @@ import basic_memory.mcp.tools # noqa: F401 # pragma: no cover
|
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
@app.command()
|
|
15
|
-
def mcp():
|
|
15
|
+
def mcp(): # pragma: no cover
|
|
16
16
|
"""Run the MCP server for Claude Desktop integration."""
|
|
17
17
|
home_dir = config.home
|
|
18
|
-
logger.info("Starting Basic Memory MCP server")
|
|
18
|
+
logger.info(f"Starting Basic Memory MCP server {basic_memory.__version__}")
|
|
19
19
|
logger.info(f"Home directory: {home_dir}")
|
|
20
20
|
mcp_server.run()
|
|
@@ -25,13 +25,11 @@ async def get_file_change_scanner(
|
|
|
25
25
|
db_type=DatabaseType.FILESYSTEM,
|
|
26
26
|
) -> FileChangeScanner: # pragma: no cover
|
|
27
27
|
"""Get sync service instance."""
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
)
|
|
32
|
-
|
|
33
|
-
file_change_scanner = FileChangeScanner(entity_repository)
|
|
34
|
-
return file_change_scanner
|
|
28
|
+
_, session_maker = await db.get_or_create_db(db_path=config.database_path, db_type=db_type)
|
|
29
|
+
|
|
30
|
+
entity_repository = EntityRepository(session_maker)
|
|
31
|
+
file_change_scanner = FileChangeScanner(entity_repository)
|
|
32
|
+
return file_change_scanner
|
|
35
33
|
|
|
36
34
|
|
|
37
35
|
def add_files_to_tree(
|
|
@@ -14,7 +14,6 @@ from rich.tree import Tree
|
|
|
14
14
|
from basic_memory import db
|
|
15
15
|
from basic_memory.cli.app import app
|
|
16
16
|
from basic_memory.config import config
|
|
17
|
-
from basic_memory.db import DatabaseType
|
|
18
17
|
from basic_memory.markdown import EntityParser
|
|
19
18
|
from basic_memory.markdown.markdown_processor import MarkdownProcessor
|
|
20
19
|
from basic_memory.repository import (
|
|
@@ -39,50 +38,50 @@ class ValidationIssue:
|
|
|
39
38
|
error: str
|
|
40
39
|
|
|
41
40
|
|
|
42
|
-
async def get_sync_service(
|
|
41
|
+
async def get_sync_service(): # pragma: no cover
|
|
43
42
|
"""Get sync service instance with all dependencies."""
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
43
|
+
_, session_maker = await db.get_or_create_db(
|
|
44
|
+
db_path=config.database_path, db_type=db.DatabaseType.FILESYSTEM
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
entity_parser = EntityParser(config.home)
|
|
48
|
+
markdown_processor = MarkdownProcessor(entity_parser)
|
|
49
|
+
file_service = FileService(config.home, markdown_processor)
|
|
50
|
+
|
|
51
|
+
# Initialize repositories
|
|
52
|
+
entity_repository = EntityRepository(session_maker)
|
|
53
|
+
observation_repository = ObservationRepository(session_maker)
|
|
54
|
+
relation_repository = RelationRepository(session_maker)
|
|
55
|
+
search_repository = SearchRepository(session_maker)
|
|
56
|
+
|
|
57
|
+
# Initialize services
|
|
58
|
+
search_service = SearchService(search_repository, entity_repository, file_service)
|
|
59
|
+
link_resolver = LinkResolver(entity_repository, search_service)
|
|
60
|
+
|
|
61
|
+
# Initialize scanner
|
|
62
|
+
file_change_scanner = FileChangeScanner(entity_repository)
|
|
63
|
+
|
|
64
|
+
# Initialize services
|
|
65
|
+
entity_service = EntityService(
|
|
66
|
+
entity_parser,
|
|
67
|
+
entity_repository,
|
|
68
|
+
observation_repository,
|
|
69
|
+
relation_repository,
|
|
70
|
+
file_service,
|
|
71
|
+
link_resolver,
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
# Create sync service
|
|
75
|
+
sync_service = SyncService(
|
|
76
|
+
scanner=file_change_scanner,
|
|
77
|
+
entity_service=entity_service,
|
|
78
|
+
entity_parser=entity_parser,
|
|
79
|
+
entity_repository=entity_repository,
|
|
80
|
+
relation_repository=relation_repository,
|
|
81
|
+
search_service=search_service,
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
return sync_service
|
|
86
85
|
|
|
87
86
|
|
|
88
87
|
def group_issues_by_directory(issues: List[ValidationIssue]) -> Dict[str, List[ValidationIssue]]:
|
|
@@ -154,6 +153,7 @@ def display_detailed_sync_results(knowledge: SyncReport):
|
|
|
154
153
|
|
|
155
154
|
async def run_sync(verbose: bool = False, watch: bool = False):
|
|
156
155
|
"""Run sync operation."""
|
|
156
|
+
|
|
157
157
|
sync_service = await get_sync_service()
|
|
158
158
|
|
|
159
159
|
# Start watching if requested
|
|
@@ -4,6 +4,10 @@ from enum import Enum, auto
|
|
|
4
4
|
from pathlib import Path
|
|
5
5
|
from typing import AsyncGenerator, Optional
|
|
6
6
|
|
|
7
|
+
from basic_memory.config import ProjectConfig
|
|
8
|
+
from alembic import command
|
|
9
|
+
from alembic.config import Config
|
|
10
|
+
|
|
7
11
|
from loguru import logger
|
|
8
12
|
from sqlalchemy import text
|
|
9
13
|
from sqlalchemy.ext.asyncio import (
|
|
@@ -14,8 +18,7 @@ from sqlalchemy.ext.asyncio import (
|
|
|
14
18
|
async_scoped_session,
|
|
15
19
|
)
|
|
16
20
|
|
|
17
|
-
from basic_memory.
|
|
18
|
-
from basic_memory.models.search import CREATE_SEARCH_INDEX
|
|
21
|
+
from basic_memory.repository.search_repository import SearchRepository
|
|
19
22
|
|
|
20
23
|
# Module level state
|
|
21
24
|
_engine: Optional[AsyncEngine] = None
|
|
@@ -35,7 +38,7 @@ class DatabaseType(Enum):
|
|
|
35
38
|
logger.info("Using in-memory SQLite database")
|
|
36
39
|
return "sqlite+aiosqlite://"
|
|
37
40
|
|
|
38
|
-
return f"sqlite+aiosqlite:///{db_path}"
|
|
41
|
+
return f"sqlite+aiosqlite:///{db_path}" # pragma: no cover
|
|
39
42
|
|
|
40
43
|
|
|
41
44
|
def get_scoped_session_factory(
|
|
@@ -69,24 +72,6 @@ async def scoped_session(
|
|
|
69
72
|
await factory.remove()
|
|
70
73
|
|
|
71
74
|
|
|
72
|
-
async def init_db() -> None:
|
|
73
|
-
"""Initialize database with required tables."""
|
|
74
|
-
if _session_maker is None: # pragma: no cover
|
|
75
|
-
raise RuntimeError("Database session maker not initialized")
|
|
76
|
-
|
|
77
|
-
logger.info("Initializing database...")
|
|
78
|
-
|
|
79
|
-
async with scoped_session(_session_maker) as session:
|
|
80
|
-
await session.execute(text("PRAGMA foreign_keys=ON"))
|
|
81
|
-
conn = await session.connection()
|
|
82
|
-
await conn.run_sync(Base.metadata.create_all)
|
|
83
|
-
|
|
84
|
-
# recreate search index
|
|
85
|
-
await session.execute(CREATE_SEARCH_INDEX)
|
|
86
|
-
|
|
87
|
-
await session.commit()
|
|
88
|
-
|
|
89
|
-
|
|
90
75
|
async def get_or_create_db(
|
|
91
76
|
db_path: Path,
|
|
92
77
|
db_type: DatabaseType = DatabaseType.FILESYSTEM,
|
|
@@ -100,9 +85,6 @@ async def get_or_create_db(
|
|
|
100
85
|
_engine = create_async_engine(db_url, connect_args={"check_same_thread": False})
|
|
101
86
|
_session_maker = async_sessionmaker(_engine, expire_on_commit=False)
|
|
102
87
|
|
|
103
|
-
# Initialize database
|
|
104
|
-
await init_db()
|
|
105
|
-
|
|
106
88
|
assert _engine is not None # for type checker
|
|
107
89
|
assert _session_maker is not None # for type checker
|
|
108
90
|
return _engine, _session_maker
|
|
@@ -122,7 +104,6 @@ async def shutdown_db() -> None: # pragma: no cover
|
|
|
122
104
|
async def engine_session_factory(
|
|
123
105
|
db_path: Path,
|
|
124
106
|
db_type: DatabaseType = DatabaseType.MEMORY,
|
|
125
|
-
init: bool = True,
|
|
126
107
|
) -> AsyncGenerator[tuple[AsyncEngine, async_sessionmaker[AsyncSession]], None]:
|
|
127
108
|
"""Create engine and session factory.
|
|
128
109
|
|
|
@@ -139,9 +120,6 @@ async def engine_session_factory(
|
|
|
139
120
|
try:
|
|
140
121
|
_session_maker = async_sessionmaker(_engine, expire_on_commit=False)
|
|
141
122
|
|
|
142
|
-
if init:
|
|
143
|
-
await init_db()
|
|
144
|
-
|
|
145
123
|
assert _engine is not None # for type checker
|
|
146
124
|
assert _session_maker is not None # for type checker
|
|
147
125
|
yield _engine, _session_maker
|
|
@@ -150,3 +128,18 @@ async def engine_session_factory(
|
|
|
150
128
|
await _engine.dispose()
|
|
151
129
|
_engine = None
|
|
152
130
|
_session_maker = None
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
async def run_migrations(app_config: ProjectConfig, database_type=DatabaseType.FILESYSTEM):
|
|
134
|
+
"""Run any pending alembic migrations."""
|
|
135
|
+
logger.info("Running database migrations...")
|
|
136
|
+
try:
|
|
137
|
+
config = Config("alembic.ini")
|
|
138
|
+
command.upgrade(config, "head")
|
|
139
|
+
logger.info("Migrations completed successfully")
|
|
140
|
+
|
|
141
|
+
_, session_maker = await get_or_create_db(app_config.database_path, database_type)
|
|
142
|
+
await SearchRepository(session_maker).init_search_index()
|
|
143
|
+
except Exception as e: # pragma: no cover
|
|
144
|
+
logger.error(f"Error running migrations: {e}")
|
|
145
|
+
raise
|
|
@@ -2,7 +2,7 @@ from httpx import ASGITransport, AsyncClient
|
|
|
2
2
|
|
|
3
3
|
from basic_memory.api.app import app as fastapi_app
|
|
4
4
|
|
|
5
|
-
BASE_URL = "
|
|
5
|
+
BASE_URL = "memory://"
|
|
6
6
|
|
|
7
7
|
# Create shared async client
|
|
8
8
|
client = AsyncClient(transport=ASGITransport(app=fastapi_app), base_url=BASE_URL)
|
|
@@ -13,6 +13,7 @@ from basic_memory.mcp.async_client import client
|
|
|
13
13
|
from basic_memory.schemas import EntityResponse, DeleteEntitiesResponse
|
|
14
14
|
from basic_memory.schemas.base import Entity
|
|
15
15
|
from basic_memory.mcp.tools.utils import call_get, call_put, call_delete
|
|
16
|
+
from basic_memory.schemas.memory import memory_url_path
|
|
16
17
|
|
|
17
18
|
|
|
18
19
|
@mcp.tool(
|
|
@@ -96,7 +97,9 @@ async def read_note(identifier: str) -> str:
|
|
|
96
97
|
Raises:
|
|
97
98
|
ValueError: If the note cannot be found
|
|
98
99
|
"""
|
|
99
|
-
|
|
100
|
+
logger.info(f"Reading note {identifier}")
|
|
101
|
+
url = memory_url_path(identifier)
|
|
102
|
+
response = await call_get(client, f"/resource/{url}")
|
|
100
103
|
return response.text
|
|
101
104
|
|
|
102
105
|
|
|
@@ -7,7 +7,6 @@ from datetime import datetime, timezone
|
|
|
7
7
|
import pytest
|
|
8
8
|
import pytest_asyncio
|
|
9
9
|
from loguru import logger
|
|
10
|
-
from sqlalchemy import text
|
|
11
10
|
from sqlalchemy.ext.asyncio import AsyncSession, AsyncEngine, async_sessionmaker
|
|
12
11
|
|
|
13
12
|
from basic_memory import db
|
|
@@ -59,10 +58,8 @@ async def engine_factory(
|
|
|
59
58
|
async with db.engine_session_factory(
|
|
60
59
|
db_path=test_config.database_path, db_type=DatabaseType.MEMORY
|
|
61
60
|
) as (engine, session_maker):
|
|
62
|
-
#
|
|
63
|
-
async with
|
|
64
|
-
await session.execute(text("PRAGMA foreign_keys=ON"))
|
|
65
|
-
conn = await session.connection()
|
|
61
|
+
# Create all tables for the DB the engine is connected to
|
|
62
|
+
async with engine.begin() as conn:
|
|
66
63
|
await conn.run_sync(Base.metadata.create_all)
|
|
67
64
|
|
|
68
65
|
yield engine, session_maker
|
|
@@ -236,3 +236,25 @@ async def test_write_note_verbose(app):
|
|
|
236
236
|
assert entity.relations[0].from_id == "test/test-note"
|
|
237
237
|
assert entity.relations[0].to_id is None
|
|
238
238
|
assert entity.relations[0].to_name == "Knowledge"
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
@pytest.mark.asyncio
|
|
242
|
+
async def test_read_note_memory_url(app):
|
|
243
|
+
"""Test reading a note using a memory:// URL.
|
|
244
|
+
|
|
245
|
+
Should:
|
|
246
|
+
- Handle memory:// URLs correctly
|
|
247
|
+
- Normalize the URL before resolving
|
|
248
|
+
- Return the note content
|
|
249
|
+
"""
|
|
250
|
+
# First create a note
|
|
251
|
+
permalink = await notes.write_note(
|
|
252
|
+
title="Memory URL Test",
|
|
253
|
+
folder="test",
|
|
254
|
+
content="Testing memory:// URL handling",
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
# Should be able to read it with a memory:// URL
|
|
258
|
+
memory_url = f"memory://{permalink}"
|
|
259
|
+
content = await notes.read_note(memory_url)
|
|
260
|
+
assert "Testing memory:// URL handling" in content
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
# Basic Memory Installer
|
|
2
|
-
|
|
3
|
-
This installer configures Basic Memory to work with Claude Desktop.
|
|
4
|
-
|
|
5
|
-
## Installation
|
|
6
|
-
|
|
7
|
-
1. Download the latest installer from the [releases page](https://github.com/basicmachines-co/basic-memory/releases)
|
|
8
|
-
2. Unzip the downloaded file
|
|
9
|
-
3. Since the app is currently unsigned, you'll need to:
|
|
10
|
-
- Right-click (or Control-click) the app
|
|
11
|
-
- Select "Open" from the context menu
|
|
12
|
-
- Click "Open" in the warning dialog
|
|
13
|
-
4. Follow the installation instructions
|
|
14
|
-
5. Restart Claude Desktop
|
|
15
|
-
|
|
16
|
-
The warning only appears the first time you open the app. Future updates will include proper code signing.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/cli/commands/import_memory_json.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/repository/observation_repository.py
RENAMED
|
File without changes
|
{basic_memory-0.2.20 → basic_memory-0.3.0}/src/basic_memory/repository/relation_repository.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|