Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
28e55ab
feat: implement rclone bisync with unified .bmignore system
phernandez Oct 1, 2025
96da166
rclone bisync wip
phernandez Oct 1, 2025
1f747c0
feat: implement Phase 1 cloud mode toggle (SPEC-9)
phernandez Oct 1, 2025
48e4449
feat: implement Phase 2 bisync updates (SPEC-9)
phernandez Oct 1, 2025
3465c69
feat: implement Phase 2.3 project auto-registration (SPEC-9)
phernandez Oct 1, 2025
88ac5c0
docs: add testing section to SPEC-9
phernandez Oct 1, 2025
b184960
fix lint
phernandez Oct 1, 2025
fe7c785
refactor project sync status info commands
phernandez Oct 1, 2025
0d4b0c6
feat: add cloud mode integration to CLI commands with integration tests
phernandez Oct 2, 2025
4405bfd
fix: restore SettingsConfigDict for OAuth authentication
phernandez Oct 2, 2025
6dc54ea
feat: add PKCE support for OAuth device flow
phernandez Oct 2, 2025
7949cb6
docs: update SPEC-9 Phase 4.3 with PKCE implementation details
phernandez Oct 2, 2025
c8b2252
fix: compare directory names instead of project names in bisync auto-…
phernandez Oct 2, 2025
f8a2fce
feat: improve bisync output visibility and feedback
phernandez Oct 2, 2025
825fb28
feat: add configurable verbosity for bisync with progress display
phernandez Oct 2, 2025
c8d77f4
set cloud_host env vars
phernandez Oct 2, 2025
ee546c7
feat: add dual-mode sync and integrity check commands
phernandez Oct 2, 2025
423e7c3
docs: update SPEC-9 with Phase 3 completion and check command
phernandez Oct 2, 2025
77b1217
docs: mark SPEC-9 phases 5-8 complete, add implementation status summary
phernandez Oct 2, 2025
eeb19ba
docs: update cloud-cli.md for SPEC-9 architecture
phernandez Oct 2, 2025
78f6a58
docs: mark SPEC-9 implementation complete
phernandez Oct 2, 2025
18941b9
feat: add type safety and comprehensive tests for bisync logic
phernandez Oct 3, 2025
34cf322
fix tests and lint
phernandez Oct 3, 2025
a4bc58b
refactor: simplify cloud commands and make bisync the default
phernandez Oct 3, 2025
ede2fb3
docs: update cloud-cli.md to reflect simplified commands
phernandez Oct 3, 2025
fcd1fe0
simplify commands, remove webdav tests
phernandez Oct 3, 2025
c6e00bf
cache bmignore list during bisync
phernandez Oct 3, 2025
2824c36
fix: Windows test failures by preserving HOME environment variable
phernandez Oct 3, 2025
50d85e4
fix: remove confusing comment about bisync/mount directory
phernandez Oct 3, 2025
6432011
update cloud_client_id to use workos PKCE app
phernandez Oct 3, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
702 changes: 448 additions & 254 deletions docs/cloud-cli.md

Large diffs are not rendered by default.

886 changes: 886 additions & 0 deletions specs/SPEC-8 TigrisFS Integration.md

Large diffs are not rendered by default.

1,114 changes: 1,114 additions & 0 deletions specs/SPEC-9 Multi-Project Bidirectional Sync Architecture.md

Large diffs are not rendered by default.

2 changes: 0 additions & 2 deletions src/basic_memory/api/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
resource,
search,
prompt_router,
webdav,
)
from basic_memory.config import ConfigManager
from basic_memory.services.initialization import initialize_file_sync, initialize_app
Expand Down Expand Up @@ -77,7 +76,6 @@ async def lifespan(app: FastAPI): # pragma: no cover
app.include_router(directory_router.router, prefix="/{project}")
app.include_router(prompt_router.router, prefix="/{project}")
app.include_router(importer_router.router, prefix="/{project}")
app.include_router(webdav.router, prefix="/{project}")

# Project resource router works accross projects
app.include_router(project.project_resource_router)
Expand Down
3 changes: 1 addition & 2 deletions src/basic_memory/api/routers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,5 @@
from . import resource_router as resource
from . import search_router as search
from . import prompt_router as prompt
from . import webdav_router as webdav

__all__ = ["knowledge", "management", "memory", "project", "resource", "search", "prompt", "webdav"]
__all__ = ["knowledge", "management", "memory", "project", "resource", "search", "prompt"]
62 changes: 58 additions & 4 deletions src/basic_memory/api/routers/project_router.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
"""Router for project management."""

import os
from fastapi import APIRouter, HTTPException, Path, Body
from fastapi import APIRouter, HTTPException, Path, Body, BackgroundTasks
from typing import Optional
from loguru import logger

from basic_memory.deps import ProjectServiceDep, ProjectPathDep
from basic_memory.schemas import ProjectInfoResponse
from basic_memory.deps import (
ProjectConfigDep,
ProjectServiceDep,
ProjectPathDep,
SyncServiceDep,
)
from basic_memory.schemas import ProjectInfoResponse, SyncReportResponse
from basic_memory.schemas.project_info import (
ProjectList,
ProjectItem,
Expand Down Expand Up @@ -97,6 +103,54 @@ async def update_project(
raise HTTPException(status_code=400, detail=str(e))


# Sync project filesystem
@project_router.post("/sync")
async def sync_project(
background_tasks: BackgroundTasks,
sync_service: SyncServiceDep,
project_config: ProjectConfigDep,
):
"""Force project filesystem sync to database.

Scans the project directory and updates the database with any new or modified files.

Args:
background_tasks: FastAPI background tasks
sync_service: Sync service for this project
project_config: Project configuration

Returns:
Response confirming sync was initiated
"""
background_tasks.add_task(sync_service.sync, project_config.home, project_config.name)
logger.info(f"Filesystem sync initiated for project: {project_config.name}")

return {
"status": "sync_started",
"message": f"Filesystem sync initiated for project '{project_config.name}'",
}


@project_router.post("/status", response_model=SyncReportResponse)
async def project_sync_status(
sync_service: SyncServiceDep,
project_config: ProjectConfigDep,
) -> SyncReportResponse:
"""Scan directory for changes compared to database state.

Args:
sync_service: Sync service for this project
project_config: Project configuration

Returns:
Scan report with details on files that need syncing
"""
logger.info(f"Scanning filesystem for project: {project_config.name}")
sync_report = await sync_service.scan(project_config.home)

return SyncReportResponse.from_sync_report(sync_report)


# List all available projects
@project_resource_router.get("/projects", response_model=ProjectList)
async def list_projects(
Expand Down Expand Up @@ -259,7 +313,7 @@ async def get_default_project(


# Synchronize projects between config and database
@project_resource_router.post("/sync", response_model=ProjectStatusResponse)
@project_resource_router.post("/config/sync", response_model=ProjectStatusResponse)
async def synchronize_projects(
project_service: ProjectServiceDep,
) -> ProjectStatusResponse:
Expand Down
Loading
Loading