Skip to main content

omgbase_sync/
lib.rs

1//! # omgbase-sync
2//!
3//! The omgbase sync layer, Rust implementation of `spec/sync`: how bytes get
4//! *between* an omgbase repository (an [`omgbase_store::Store`]) and the
5//! places they live — the [`workspace`] on disk that holds the database, the
6//! source [`registry`] that says where a repo's bytes come from, the
7//! [`settings`] layers, the [`checkpoint`] rows and the filesystem fast path
8//! ([`freshness`] sweep, disk drift, [`recovery`]) over a [`fs::FileSystem`]
9//! seam, the adapter stdio protocol client ([`external`]), the [`driver`] and
10//! the [`coordinator`] over an [`engine::EngineClient`] — in-process, or the
11//! [`mcp_client`] that reaches a remote engine over MCP (stdio, or Streamable
12//! HTTP behind the `http` feature) — and the advisory [`lock`]s. [`pipe`] is an in-memory pipe with a scripted adapter, for
13//! driving the protocol client without a process. The reconciliation itself is the store's (`spec/store` §5).
14//!
15//! ```no_run
16//! use omgbase_reconcile::Config;
17//! use omgbase_store::Store;
18//! use omgbase_sync::{fs::RealFileSystem, registry, freshness};
19//!
20//! let mut store = Store::open(".omgbase/omgbase.db")?;
21//! let repo = registry::ensure_repo(&mut store, "notes", Some("/home/me/notes"))?;
22//! let sweep = freshness::freshness_sweep(
23//!     &mut store, &repo, &RealFileSystem, "/home/me/notes".as_ref(),
24//!     "2026-09-26T10:00:00.000Z", None, &Config::default(),
25//! )?;
26//! println!("{} files scanned, changed: {}", sweep.scanned, sweep.changed);
27//! # Ok::<(), omgbase_sync::Error>(())
28//! ```
29
30#![deny(unsafe_code)]
31
32pub mod admin;
33pub mod checkpoint;
34pub mod coordinator;
35pub mod driver;
36pub mod engine;
37pub mod error;
38pub mod external;
39pub mod freshness;
40pub mod fs;
41pub mod lock;
42pub mod mcp_client;
43pub mod pipe;
44pub mod recovery;
45pub mod registry;
46pub mod settings;
47pub mod source;
48pub mod workspace;
49
50pub use admin::{DiskStatus, RepoStatus, SyncStatus, repos_status, sync_status};
51pub use checkpoint::{CheckpointResult, finish_checkpoint, process_checkpoint};
52pub use coordinator::{Coordinator, SyncInSummary, SyncOutSummary};
53pub use driver::{AttachResult, attach_source, reconcile_changes};
54pub use engine::{DocBytes, EngineClient, InProcessEngineClient};
55pub use error::{Error, Result};
56pub use external::ExternalSource;
57pub use freshness::{
58    DiskDrift, SweepPlan, SweepResult, detect_disk_drift, freshness_sweep, rebuild_file_stats,
59    record_file_stat, sweep_plan,
60};
61pub use fs::{FileStat, FileSystem, MemFileSystem, RealFileSystem, is_ignored_dir};
62pub use lock::{WatchLease, WriterLock, WriterLockOptions, pid_alive, with_writer_lock};
63pub use mcp_client::{EngineSpec, McpEngineClient, ToolResult, parse_engine_spec};
64pub use omgbase_store::{ChangesPage, CommitDigest, DeleteOutcome, DigestRevision, ObserveOutcome};
65pub use recovery::{RecoveryResult, recover_repo};
66pub use registry::{
67    AdapterRow, SourceRow, attach, create_source, delete_source, detach, ensure_adapter,
68    ensure_repo, list_adapters, list_sources, render_config_flags, source_by_name,
69    sources_for_repo,
70};
71pub use settings::{
72    Settings, deep_merge, repo_own_settings, resolve_settings, workspace_settings,
73    write_repo_settings, write_workspace_settings,
74};
75pub use source::{
76    Readiness, SourceCapabilities, SourceEntry, SourceIdentity, SourceItem, SyncSource, WatchEvent,
77    wait_ready,
78};
79pub use workspace::{RepoRow, RepoSelection, Workspace, select_repo};
80
81/// The `spec/sync/VERSION` this crate implements (`major.minor`).
82pub const SPEC_VERSION: &str = "1.2";
83
84/// The adapter protocol number the handshake must carry (`spec/sync` §5).
85pub const PROTOCOL_VERSION: u64 = 1;
86
87/// The current time as the store writes it (`spec/store` §2.4:
88/// `YYYY-MM-DDTHH:MM:SS.fffZ`).
89#[must_use]
90pub fn now_ts() -> String {
91    let ms = std::time::SystemTime::now()
92        .duration_since(std::time::UNIX_EPOCH)
93        .map(|d| i64::try_from(d.as_millis()).unwrap_or(i64::MAX))
94        .unwrap_or(0);
95    omgbase_store::time::format_ms(ms)
96}