feat: Add Brain Monitor dashboard and live API stats
This commit is contained in:
1 parent
3239e32866
commit
18fd05bb11
10 files changed
+665
-73
No files matched your search
Generated
+67
-1
@@ -1171,6 +1171,12 @@ dependencies = [
|
|||||||
"zeroize",
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lazy_static"
|
||||||
|
version = "1.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "levenshtein_automata"
|
name = "levenshtein_automata"
|
||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
@@ -1267,10 +1273,11 @@ dependencies = [
|
|||||||
"rust-mcp-sdk",
|
"rust-mcp-sdk",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"strsim",
|
|
||||||
"tantivy",
|
"tantivy",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-util",
|
"tokio-util",
|
||||||
|
"tracing",
|
||||||
|
"tracing-subscriber",
|
||||||
"uuid",
|
"uuid",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -1358,6 +1365,15 @@ dependencies = [
|
|||||||
"minimal-lexical",
|
"minimal-lexical",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nu-ansi-term"
|
||||||
|
version = "0.50.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
|
||||||
|
dependencies = [
|
||||||
|
"windows-sys 0.61.2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-bigint"
|
name = "num-bigint"
|
||||||
version = "0.4.8"
|
version = "0.4.8"
|
||||||
@@ -2026,6 +2042,15 @@ dependencies = [
|
|||||||
"digest",
|
"digest",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sharded-slab"
|
||||||
|
version = "0.1.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6"
|
||||||
|
dependencies = [
|
||||||
|
"lazy_static",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "shlex"
|
name = "shlex"
|
||||||
version = "2.0.1"
|
version = "2.0.1"
|
||||||
@@ -2335,6 +2360,15 @@ dependencies = [
|
|||||||
"syn 3.0.5",
|
"syn 3.0.5",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thread_local"
|
||||||
|
version = "1.1.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1ad99c4c6d32803332c548b1af0540b357b3f5fc0be8f6c6bfe8b2e6ae784070"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "time"
|
name = "time"
|
||||||
version = "0.3.55"
|
version = "0.3.55"
|
||||||
@@ -2531,6 +2565,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a"
|
checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"once_cell",
|
"once_cell",
|
||||||
|
"valuable",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tracing-log"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
|
||||||
|
dependencies = [
|
||||||
|
"log",
|
||||||
|
"once_cell",
|
||||||
|
"tracing-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tracing-subscriber"
|
||||||
|
version = "0.3.23"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319"
|
||||||
|
dependencies = [
|
||||||
|
"nu-ansi-term",
|
||||||
|
"sharded-slab",
|
||||||
|
"smallvec",
|
||||||
|
"thread_local",
|
||||||
|
"tracing-core",
|
||||||
|
"tracing-log",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2642,6 +2702,12 @@ dependencies = [
|
|||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "valuable"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "version_check"
|
name = "version_check"
|
||||||
version = "0.9.5"
|
version = "0.9.5"
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
Finished `dev` profile [unoptimized + debuginfo] target(s) in 14.64s
|
||||||
@@ -0,0 +1,312 @@
|
|||||||
|
Blocking waiting for file lock on package cache
|
||||||
|
Blocking waiting for file lock on package cache
|
||||||
|
Compiling proc-macro2 v1.0.107
|
||||||
|
Compiling quote v1.0.47
|
||||||
|
Compiling unicode-ident v1.0.24
|
||||||
|
Compiling getrandom v0.4.3
|
||||||
|
Compiling serde_core v1.0.229
|
||||||
|
Checking windows-link v0.2.1
|
||||||
|
Compiling cfg-if v1.0.4
|
||||||
|
Compiling shlex v2.0.1
|
||||||
|
Compiling find-msvc-tools v0.1.12
|
||||||
|
Checking smallvec v1.16.0
|
||||||
|
Checking stable_deref_trait v1.2.1
|
||||||
|
Checking windows-sys v0.61.2
|
||||||
|
Checking pin-project-lite v0.2.17
|
||||||
|
Checking futures-core v0.3.34
|
||||||
|
Checking memchr v2.8.3
|
||||||
|
Checking itoa v1.0.18
|
||||||
|
Compiling serde v1.0.229
|
||||||
|
Checking bytes v1.12.1
|
||||||
|
Checking once_cell v1.21.4
|
||||||
|
Checking futures-sink v0.3.34
|
||||||
|
Compiling parking_lot_core v0.9.12
|
||||||
|
Checking scopeguard v1.2.0
|
||||||
|
Checking slab v0.4.12
|
||||||
|
Checking mio v1.2.3
|
||||||
|
Checking socket2 v0.6.5
|
||||||
|
Checking log v0.4.34
|
||||||
|
Checking futures-channel v0.3.34
|
||||||
|
Compiling version_check v0.9.5
|
||||||
|
Compiling jobserver v0.1.35
|
||||||
|
Checking lock_api v0.4.14
|
||||||
|
Compiling zmij v1.0.23
|
||||||
|
Checking futures-task v0.3.34
|
||||||
|
Checking futures-io v0.3.34
|
||||||
|
Compiling num-conv v0.2.2
|
||||||
|
Compiling time-core v0.1.9
|
||||||
|
Compiling cc v1.4.5
|
||||||
|
Compiling autocfg v1.5.1
|
||||||
|
Checking deranged v0.5.8
|
||||||
|
Checking http v1.5.0
|
||||||
|
Checking tracing-core v0.1.36
|
||||||
|
Compiling syn v3.0.5
|
||||||
|
Compiling syn v2.0.119
|
||||||
|
Checking percent-encoding v2.3.2
|
||||||
|
Checking litemap v0.8.3
|
||||||
|
Compiling time-macros v0.2.32
|
||||||
|
Checking writeable v0.6.4
|
||||||
|
Checking powerfmt v0.2.0
|
||||||
|
Checking equivalent v1.0.2
|
||||||
|
Checking parking_lot v0.12.5
|
||||||
|
Checking utf8_iter v1.0.4
|
||||||
|
Compiling icu_normalizer_data v2.3.0
|
||||||
|
Compiling icu_properties_data v2.3.0
|
||||||
|
Checking fnv v1.0.7
|
||||||
|
Compiling serde_json v1.0.151
|
||||||
|
Checking http-body v1.1.0
|
||||||
|
Checking hashbrown v0.17.1
|
||||||
|
Compiling httparse v1.10.1
|
||||||
|
Checking base64 v0.22.1
|
||||||
|
Compiling synstructure v0.13.2
|
||||||
|
Checking tower-service v0.3.3
|
||||||
|
Compiling ring v0.17.14
|
||||||
|
Compiling num-traits v0.2.19
|
||||||
|
Checking indexmap v2.14.2
|
||||||
|
Checking time v0.3.55
|
||||||
|
Checking try-lock v0.2.5
|
||||||
|
Compiling serde_derive v1.0.229
|
||||||
|
Compiling zerovec-derive v0.11.6
|
||||||
|
Compiling tokio-macros v2.7.2
|
||||||
|
Compiling zerofrom-derive v0.1.7
|
||||||
|
Compiling yoke-derive v0.8.2
|
||||||
|
Compiling displaydoc v0.2.7
|
||||||
|
Compiling futures-macro v0.3.34
|
||||||
|
Compiling tracing-attributes v0.1.31
|
||||||
|
Compiling zeroize_derive v1.5.0
|
||||||
|
Checking tokio v1.53.1
|
||||||
|
Compiling libc v0.2.189
|
||||||
|
Checking atomic-waker v1.1.2
|
||||||
|
Checking futures-util v0.3.34
|
||||||
|
Checking subtle v2.6.1
|
||||||
|
Checking zerofrom v0.1.8
|
||||||
|
Checking want v0.3.1
|
||||||
|
Checking zeroize v1.9.0
|
||||||
|
Checking tracing v0.1.44
|
||||||
|
Checking form_urlencoded v1.2.2
|
||||||
|
Checking yoke v0.8.3
|
||||||
|
Checking getrandom v0.2.17
|
||||||
|
Checking httpdate v1.0.3
|
||||||
|
Checking untrusted v0.9.0
|
||||||
|
Checking rustls-pki-types v1.15.1
|
||||||
|
Compiling generic-array v0.14.7
|
||||||
|
Checking sync_wrapper v1.0.2
|
||||||
|
Checking tower-layer v0.3.3
|
||||||
|
Checking tokio-util v0.7.19
|
||||||
|
Checking zerovec v0.11.8
|
||||||
|
Checking zerotrie v0.2.5
|
||||||
|
Compiling rustls v0.23.44
|
||||||
|
Compiling pkg-config v0.3.34
|
||||||
|
Checking ipnet v2.12.2
|
||||||
|
Compiling async-trait v0.1.92
|
||||||
|
Compiling cmake v0.1.58
|
||||||
|
Compiling cookie v0.18.2
|
||||||
|
Checking h2 v0.4.19
|
||||||
|
Checking tinystr v0.8.4
|
||||||
|
Checking potential_utf v0.1.6
|
||||||
|
Compiling dunce v1.0.5
|
||||||
|
Checking mime v0.3.17
|
||||||
|
Compiling zstd-sys v2.1.0+zstd.1.5.7
|
||||||
|
Compiling unicase v2.9.0
|
||||||
|
Checking icu_locale_core v2.3.0
|
||||||
|
Compiling thiserror v2.0.20
|
||||||
|
Checking icu_collections v2.3.0
|
||||||
|
Compiling fs_extra v1.3.0
|
||||||
|
Compiling crossbeam-utils v0.8.23
|
||||||
|
Checking typenum v1.20.1
|
||||||
|
Compiling mime_guess v2.0.5
|
||||||
|
Checking hyper v1.11.1
|
||||||
|
Checking tower v0.5.3
|
||||||
|
Checking rustls-webpki v0.103.15
|
||||||
|
Checking icu_provider v2.3.1
|
||||||
|
Compiling thiserror-impl v2.0.20
|
||||||
|
Compiling aws-lc-sys v0.45.0
|
||||||
|
Checking http-body-util v0.1.5
|
||||||
|
Checking icu_normalizer v2.3.0
|
||||||
|
Checking icu_properties v2.3.0
|
||||||
|
Checking hyper-util v0.1.20
|
||||||
|
Compiling litrs v1.0.0
|
||||||
|
Checking ryu v1.0.23
|
||||||
|
Checking psl-types v2.0.11
|
||||||
|
Checking either v1.18.0
|
||||||
|
Compiling crunchy v0.2.4
|
||||||
|
Checking idna_adapter v1.2.2
|
||||||
|
Checking serde_urlencoded v0.7.1
|
||||||
|
Compiling document-features v0.2.12
|
||||||
|
Checking idna v1.1.0
|
||||||
|
Checking webpki-roots v1.0.9
|
||||||
|
Compiling ident_case v1.0.1
|
||||||
|
Checking tokio-rustls v0.26.5
|
||||||
|
Checking byteorder v1.5.0
|
||||||
|
Checking url v2.5.8
|
||||||
|
Checking publicsuffix v2.3.0
|
||||||
|
Checking bitflags v2.13.1
|
||||||
|
Compiling crossbeam-epoch v0.9.21
|
||||||
|
Compiling windows_x86_64_msvc v0.52.6
|
||||||
|
Compiling zstd-safe v7.3.0
|
||||||
|
Checking regex-syntax v0.8.11
|
||||||
|
Compiling strsim v0.11.1
|
||||||
|
Checking hyper-rustls v0.27.9
|
||||||
|
Checking cookie_store v0.22.1
|
||||||
|
Checking tower-http v0.6.11
|
||||||
|
Compiling darling_core v0.24.1
|
||||||
|
Checking block-buffer v0.10.4
|
||||||
|
Checking crypto-common v0.1.7
|
||||||
|
Checking num-integer v0.1.47
|
||||||
|
Checking ownedbytes v0.9.0
|
||||||
|
Compiling crossbeam-deque v0.8.8
|
||||||
|
Compiling typeid v1.0.3
|
||||||
|
Checking once_cell_polyfill v1.70.2
|
||||||
|
Compiling aws-lc-rs v1.18.1
|
||||||
|
Checking utf8parse v0.2.2
|
||||||
|
Compiling prettyplease v0.3.0
|
||||||
|
Checking anstyle v1.0.14
|
||||||
|
Checking tantivy-common v0.11.0
|
||||||
|
Checking anstyle-parse v1.0.0
|
||||||
|
Compiling darling_macro v0.24.1
|
||||||
|
Checking anstyle-wincon v3.0.11
|
||||||
|
Checking num-bigint v0.4.8
|
||||||
|
Checking digest v0.10.7
|
||||||
|
Checking reqwest v0.12.28
|
||||||
|
Checking bitpacking v0.9.3
|
||||||
|
Checking futures-executor v0.3.34
|
||||||
|
Compiling fs-err v3.3.1
|
||||||
|
Checking anstyle-query v1.1.5
|
||||||
|
Compiling rayon-core v1.13.0
|
||||||
|
Checking colorchoice v1.0.5
|
||||||
|
Checking is_terminal_polyfill v1.70.2
|
||||||
|
Checking utf8-ranges v1.0.5
|
||||||
|
Compiling rustversion v1.0.23
|
||||||
|
Checking untrusted v0.7.1
|
||||||
|
Compiling erased-serde v0.4.10
|
||||||
|
Checking futures v0.3.34
|
||||||
|
Checking tantivy-bitpacker v0.10.0
|
||||||
|
Checking anstream v1.0.0
|
||||||
|
Checking zstd v0.13.3
|
||||||
|
Checking tantivy-fst v0.5.0
|
||||||
|
Checking simple_asn1 v0.6.4
|
||||||
|
Checking windows-targets v0.52.6
|
||||||
|
Compiling darling v0.24.1
|
||||||
|
Checking uuid v1.26.0
|
||||||
|
Checking itertools v0.14.0
|
||||||
|
Checking tokio-stream v0.1.19
|
||||||
|
Checking rust-mcp-schema v2.0.0
|
||||||
|
Checking pem v3.0.6
|
||||||
|
Compiling crc32fast v1.5.1
|
||||||
|
Checking minimal-lexical v0.2.1
|
||||||
|
Checking signature v2.2.0
|
||||||
|
Checking murmurhash32 v0.3.1
|
||||||
|
Checking clap_lex v1.1.0
|
||||||
|
Compiling heck v0.5.0
|
||||||
|
Checking cpufeatures v0.2.17
|
||||||
|
Checking allocator-api2 v0.2.21
|
||||||
|
Checking foldhash v0.2.0
|
||||||
|
Compiling typetag v0.2.23
|
||||||
|
Compiling winapi v0.3.9
|
||||||
|
Checking nom v7.1.3
|
||||||
|
Checking tantivy-stacker v0.7.0
|
||||||
|
Checking sha2 v0.10.9
|
||||||
|
Compiling clap_derive v4.6.4
|
||||||
|
Checking tantivy-sstable v0.7.0
|
||||||
|
Checking hashbrown v0.16.1
|
||||||
|
Checking clap_builder v4.6.6
|
||||||
|
Compiling rust-mcp-macros v2.0.0
|
||||||
|
Compiling bon-macros v3.10.1
|
||||||
|
Checking rust-mcp-transport v2.0.0
|
||||||
|
Checking windows-sys v0.59.0
|
||||||
|
Checking hmac v0.12.1
|
||||||
|
Checking regex-automata v0.4.18
|
||||||
|
Checking axum-core v0.5.6
|
||||||
|
Checking ordered-float v5.5.0
|
||||||
|
Compiling typetag-impl v0.2.23
|
||||||
|
Checking serde_path_to_error v0.1.20
|
||||||
|
Checking fastrand v2.5.0
|
||||||
|
Checking inventory v0.3.24
|
||||||
|
Checking downcast-rs v2.0.2
|
||||||
|
Checking matchit v0.8.4
|
||||||
|
Checking fastdivide v0.4.2
|
||||||
|
Checking option-ext v0.2.0
|
||||||
|
Checking base64 v0.23.1
|
||||||
|
Checking fs4 v0.13.1
|
||||||
|
Checking arc-swap v1.9.2
|
||||||
|
Checking tantivy-columnar v0.7.0
|
||||||
|
Checking dirs-sys v0.5.0
|
||||||
|
Checking tempfile v3.27.0
|
||||||
|
Checking clap v4.6.6
|
||||||
|
Checking regex v1.13.1
|
||||||
|
Checking tantivy-query-grammar v0.26.0
|
||||||
|
Checking axum v0.8.9
|
||||||
|
Checking rayon v1.12.0
|
||||||
|
Checking axum-server v0.8.0
|
||||||
|
Checking lru v0.16.4
|
||||||
|
Checking crossbeam-channel v0.5.17
|
||||||
|
Checking rust-stemmers v1.2.0
|
||||||
|
Checking sketches-ddsketch v0.4.1
|
||||||
|
Checking tantivy-tokenizer-api v0.7.0
|
||||||
|
Checking measure_time v0.9.0
|
||||||
|
Checking aho-corasick v1.1.5
|
||||||
|
Checking htmlescape v0.3.1
|
||||||
|
Checking lz4_flex v0.13.1
|
||||||
|
Checking bon v3.10.1
|
||||||
|
Checking memmap2 v0.9.11
|
||||||
|
Checking datasketches v0.2.0
|
||||||
|
Checking levenshtein_automata v0.2.1
|
||||||
|
Checking rustc-hash v2.1.3
|
||||||
|
Checking oneshot v0.1.13
|
||||||
|
Checking census v0.4.2
|
||||||
|
Checking dirs v6.0.0
|
||||||
|
Checking glob v0.3.4
|
||||||
|
Checking mcp-memory-stub v0.1.0 (C:\Users\reazul.ashraf\workspace\rust\mcp-memory\stub)
|
||||||
|
Checking tantivy v0.26.1
|
||||||
|
warning: this can be `std::io::Error::other(_)`
|
||||||
|
--> stub\src\main.rs:76:72
|
||||||
|
|
|
||||||
|
76 | let stream = resp.bytes_stream().map(|res| res.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e)));
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.98.0/index.html#io_other_error
|
||||||
|
= note: `#[warn(clippy::io_other_error)]` on by default
|
||||||
|
help: use `std::io::Error::other`
|
||||||
|
|
|
||||||
|
76 - let stream = resp.bytes_stream().map(|res| res.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e)));
|
||||||
|
76 + let stream = resp.bytes_stream().map(|res| res.map_err(|e| std::io::Error::other(e)));
|
||||||
|
|
|
||||||
|
|
||||||
|
warning: stripping a prefix manually
|
||||||
|
--> stub\src\main.rs:93:40
|
||||||
|
|
|
||||||
|
93 | println!("{}", &trimmed[6..]);
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
note: the prefix was tested here
|
||||||
|
--> stub\src\main.rs:91:24
|
||||||
|
|
|
||||||
|
91 | } else if trimmed.starts_with("data: ") {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.98.0/index.html#manual_strip
|
||||||
|
= note: `#[warn(clippy::manual_strip)]` on by default
|
||||||
|
help: try using the `strip_prefix` method
|
||||||
|
|
|
||||||
|
91 ~ } else if let Some(<stripped>) = trimmed.strip_prefix("data: ") {
|
||||||
|
92 | if is_message {
|
||||||
|
93 ~ println!("{}", <stripped>);
|
||||||
|
94 | is_message = false;
|
||||||
|
95 | } else if is_endpoint {
|
||||||
|
96 ~ let ep = <stripped>;
|
||||||
|
|
|
||||||
|
|
||||||
|
warning: redundant pattern matching
|
||||||
|
--> stub\src\main.rs:117:16
|
||||||
|
|
|
||||||
|
117 | if let Err(_) = std::net::TcpStream::connect(cli.target.replace("http://", "").replace("https://", "")) {
|
||||||
|
| ^^^^^^
|
||||||
|
|
|
||||||
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.98.0/index.html#redundant_pattern_matching
|
||||||
|
= note: `#[warn(clippy::redundant_pattern_matching)]` on by default
|
||||||
|
help: consider using `is_err()`
|
||||||
|
|
|
||||||
|
117 - if let Err(_) = std::net::TcpStream::connect(cli.target.replace("http://", "").replace("https://", "")) {
|
||||||
|
117 + if std::net::TcpStream::connect(cli.target.replace("http://", "").replace("https://", "")).is_err() {
|
||||||
|
|
|
||||||
|
|
||||||
|
warning: `mcp-memory-stub` (bin "mcp-memory-stub") generated 3 warnings (run `cargo clippy --fix --bin "mcp-memory-stub" -p mcp-memory-stub -- ` to apply 2 suggestions)
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
import urllib.request
|
||||||
|
import json
|
||||||
|
import threading
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
|
||||||
|
sse_url = "http://localhost:3000/sse"
|
||||||
|
|
||||||
|
def call_mcp(method, params):
|
||||||
|
req = urllib.request.Request(sse_url)
|
||||||
|
with urllib.request.urlopen(req) as response:
|
||||||
|
endpoint = None
|
||||||
|
# read the SSE stream
|
||||||
|
for line_bytes in response:
|
||||||
|
line = line_bytes.decode('utf-8').strip()
|
||||||
|
if line.startswith("data: /messages"):
|
||||||
|
endpoint = "http://localhost:3000" + line.split("data: ")[1].strip()
|
||||||
|
break
|
||||||
|
|
||||||
|
if not endpoint:
|
||||||
|
print("Failed to get endpoint")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
print(f"Got endpoint: {endpoint}")
|
||||||
|
|
||||||
|
payload = {
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": 1,
|
||||||
|
"method": "tools/call",
|
||||||
|
"params": {
|
||||||
|
"name": method,
|
||||||
|
"arguments": params
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
post_req = urllib.request.Request(endpoint, data=json.dumps(payload).encode('utf-8'), headers={'Content-Type': 'application/json'})
|
||||||
|
with urllib.request.urlopen(post_req) as post_resp:
|
||||||
|
print(f"POST status: {post_resp.status}")
|
||||||
|
|
||||||
|
# continue reading SSE for response
|
||||||
|
for line_bytes in response:
|
||||||
|
line = line_bytes.decode('utf-8').strip()
|
||||||
|
if line.startswith("data: "):
|
||||||
|
data = line[6:]
|
||||||
|
if data == "ping": continue
|
||||||
|
try:
|
||||||
|
msg = json.loads(data)
|
||||||
|
if msg.get("id") == 1:
|
||||||
|
print("RESULT:")
|
||||||
|
print(json.dumps(msg, indent=2))
|
||||||
|
return
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
import sys
|
||||||
|
if __name__ == "__main__":
|
||||||
|
method = sys.argv[1]
|
||||||
|
params = json.loads(sys.argv[2])
|
||||||
|
call_mcp(method, params)
|
||||||
+2
-1
@@ -15,8 +15,9 @@ rust-mcp-axum = "2.0.0"
|
|||||||
rust-mcp-sdk = "2.0.0"
|
rust-mcp-sdk = "2.0.0"
|
||||||
serde = { version = "1.0.229", features = ["derive"] }
|
serde = { version = "1.0.229", features = ["derive"] }
|
||||||
serde_json = "1.0.151"
|
serde_json = "1.0.151"
|
||||||
strsim = "0.11.1"
|
|
||||||
tantivy = "0.26.1"
|
tantivy = "0.26.1"
|
||||||
tokio = { version = "1.53.1", features = ["full"] }
|
tokio = { version = "1.53.1", features = ["full"] }
|
||||||
tokio-util = { version = "0.7.19", features = ["io"] }
|
tokio-util = { version = "0.7.19", features = ["io"] }
|
||||||
|
tracing = "0.1.44"
|
||||||
|
tracing-subscriber = "0.3.23"
|
||||||
uuid = { version = "1.26.0", features = ["v4"] }
|
uuid = { version = "1.26.0", features = ["v4"] }
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Brain Monitor</title>
|
||||||
|
<style>
|
||||||
|
body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; padding: 40px; background-color: #f0f2f5; color: #333; }
|
||||||
|
h1 { color: #2c3e50; text-align: center; margin-bottom: 30px; }
|
||||||
|
.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 20px; max-width: 800px; margin: 0 auto; }
|
||||||
|
.stat-card { background: white; padding: 20px; border-radius: 8px; box-shadow: 0 4px 6px rgba(0,0,0,0.05); text-align: center; transition: transform 0.2s ease; }
|
||||||
|
.stat-card:hover { transform: translateY(-5px); }
|
||||||
|
.stat-value { font-size: 2.5em; font-weight: bold; color: #3498db; margin: 10px 0; }
|
||||||
|
.stat-label { font-size: 1.1em; color: #7f8c8d; text-transform: uppercase; letter-spacing: 1px; }
|
||||||
|
.status-dot { display: inline-block; width: 10px; height: 10px; background-color: #2ecc71; border-radius: 50%; margin-right: 8px; box-shadow: 0 0 5px #2ecc71; }
|
||||||
|
.header-bar { max-width: 800px; margin: 0 auto 20px; display: flex; justify-content: space-between; align-items: center; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="header-bar">
|
||||||
|
<h1>🧠 Antigravity Brain Monitor</h1>
|
||||||
|
<div><span class="status-dot"></span>System Online</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid">
|
||||||
|
<div class="stat-card">
|
||||||
|
<div class="stat-label">Entities</div>
|
||||||
|
<div class="stat-value" id="val-entities">-</div>
|
||||||
|
</div>
|
||||||
|
<div class="stat-card">
|
||||||
|
<div class="stat-label">Relations</div>
|
||||||
|
<div class="stat-value" id="val-relations">-</div>
|
||||||
|
</div>
|
||||||
|
<div class="stat-card">
|
||||||
|
<div class="stat-label">Active Tasks</div>
|
||||||
|
<div class="stat-value" id="val-tasks">-</div>
|
||||||
|
</div>
|
||||||
|
<div class="stat-card">
|
||||||
|
<div class="stat-label">Snippets</div>
|
||||||
|
<div class="stat-value" id="val-snippets">-</div>
|
||||||
|
</div>
|
||||||
|
<div class="stat-card">
|
||||||
|
<div class="stat-label">Tech Debt</div>
|
||||||
|
<div class="stat-value" id="val-tech_debts">-</div>
|
||||||
|
</div>
|
||||||
|
<div class="stat-card">
|
||||||
|
<div class="stat-label">ADRs</div>
|
||||||
|
<div class="stat-value" id="val-adrs">-</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
async function fetchStats() {
|
||||||
|
try {
|
||||||
|
const response = await fetch('/api/stats');
|
||||||
|
const data = await response.json();
|
||||||
|
|
||||||
|
document.getElementById('val-entities').innerText = data.entities;
|
||||||
|
document.getElementById('val-relations').innerText = data.relations;
|
||||||
|
document.getElementById('val-tasks').innerText = data.tasks;
|
||||||
|
document.getElementById('val-snippets').innerText = data.snippets;
|
||||||
|
document.getElementById('val-tech_debts').innerText = data.tech_debts;
|
||||||
|
document.getElementById('val-adrs').innerText = data.adrs;
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Failed to fetch stats:", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initial fetch
|
||||||
|
fetchStats();
|
||||||
|
// Poll every 2 seconds
|
||||||
|
setInterval(fetchStats, 2000);
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
+56
-64
@@ -120,6 +120,9 @@ impl ServerHandler for MemoryHandler {
|
|||||||
} {
|
} {
|
||||||
let entity: Entity = e;
|
let entity: Entity = e;
|
||||||
if !entity.name.is_empty() {
|
if !entity.name.is_empty() {
|
||||||
|
if let Ok(idx) = self.state.search_index.read() {
|
||||||
|
let _ = idx.index_entity(&entity);
|
||||||
|
}
|
||||||
g.entities.insert(entity.name.clone(), entity);
|
g.entities.insert(entity.name.clone(), entity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -267,29 +270,19 @@ impl ServerHandler for MemoryHandler {
|
|||||||
}
|
}
|
||||||
"search_nodes" => {
|
"search_nodes" => {
|
||||||
let req: SearchNodesTool = parse_args(args)?;
|
let req: SearchNodesTool = parse_args(args)?;
|
||||||
let query = req.query.to_lowercase();
|
let matches = if let Ok(idx) = self.state.search_index.read() {
|
||||||
let tokens: Vec<&str> = query.split_whitespace().collect();
|
idx.search(&req.query, req.namespace.as_deref()).unwrap_or_default()
|
||||||
|
} else {
|
||||||
|
vec![]
|
||||||
|
};
|
||||||
|
|
||||||
let mut result = KnowledgeGraph::default();
|
let mut result = KnowledgeGraph::default();
|
||||||
for (name, e) in self.state.get_full_graph().entities {
|
let full = self.state.get_full_graph();
|
||||||
if let Some(ns) = &req.namespace
|
for (id, doc_type) in matches {
|
||||||
&& e.namespace != *ns
|
if doc_type == "entity" {
|
||||||
{
|
if let Some(e) = full.entities.get(&id) {
|
||||||
continue;
|
result.entities.insert(id, e.clone());
|
||||||
}
|
}
|
||||||
let name_low = name.to_lowercase();
|
|
||||||
let type_low = e.entity_type.to_lowercase();
|
|
||||||
let full_txt = format!(
|
|
||||||
"{} {} {}",
|
|
||||||
name_low,
|
|
||||||
type_low,
|
|
||||||
e.observations.join(" ").to_lowercase()
|
|
||||||
);
|
|
||||||
let matched = full_txt.contains(&query)
|
|
||||||
|| (!tokens.is_empty() && tokens.iter().all(|&t| full_txt.contains(t)))
|
|
||||||
|| strsim::jaro_winkler(&name_low, &query) > 0.85
|
|
||||||
|| strsim::jaro_winkler(&type_low, &query) > 0.85;
|
|
||||||
if matched {
|
|
||||||
result.entities.insert(name, e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let data = serde_json::to_string(&result).unwrap_or_default();
|
let data = serde_json::to_string(&result).unwrap_or_default();
|
||||||
@@ -456,8 +449,7 @@ impl ServerHandler for MemoryHandler {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.as_secs();
|
.as_secs();
|
||||||
let id = uuid::Uuid::new_v4().to_string();
|
let id = uuid::Uuid::new_v4().to_string();
|
||||||
self.state.tasks.modify(|tasks| {
|
let task = Task {
|
||||||
tasks.push(Task {
|
|
||||||
id: id.clone(),
|
id: id.clone(),
|
||||||
title: req.title,
|
title: req.title,
|
||||||
status: "pending".to_string(),
|
status: "pending".to_string(),
|
||||||
@@ -465,7 +457,12 @@ impl ServerHandler for MemoryHandler {
|
|||||||
created_at: now,
|
created_at: now,
|
||||||
updated_at: now,
|
updated_at: now,
|
||||||
git_branch: req.git_branch,
|
git_branch: req.git_branch,
|
||||||
});
|
};
|
||||||
|
if let Ok(idx) = self.state.search_index.read() {
|
||||||
|
let _ = idx.index_task(&task);
|
||||||
|
}
|
||||||
|
self.state.tasks.modify(|tasks| {
|
||||||
|
tasks.push(task);
|
||||||
});
|
});
|
||||||
Ok(ServerResult::from(CallToolResult::text_content(vec![
|
Ok(ServerResult::from(CallToolResult::text_content(vec![
|
||||||
format!("Task added with ID: {}", id).into(),
|
format!("Task added with ID: {}", id).into(),
|
||||||
@@ -1098,47 +1095,42 @@ impl ServerHandler for MemoryHandler {
|
|||||||
}
|
}
|
||||||
"omni_search" => {
|
"omni_search" => {
|
||||||
let req: OmniSearchTool = parse_args(args)?;
|
let req: OmniSearchTool = parse_args(args)?;
|
||||||
|
let matches = if let Ok(idx) = self.state.search_index.read() {
|
||||||
|
idx.search(&req.query, req.namespace.as_deref()).unwrap_or_default()
|
||||||
|
} else {
|
||||||
|
vec![]
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut kg = KnowledgeGraph::default();
|
||||||
|
let mut tasks = Vec::new();
|
||||||
|
let mut snippets = Vec::new();
|
||||||
|
let mut adrs = Vec::new();
|
||||||
|
|
||||||
|
let full = self.state.get_full_graph();
|
||||||
|
for (id, doc_type) in &matches {
|
||||||
|
if doc_type == "entity" {
|
||||||
|
if let Some(e) = full.entities.get(id) {
|
||||||
|
kg.entities.insert(id.clone(), e.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for t in self.state.tasks.read() {
|
||||||
|
if matches.iter().any(|(id, typ)| id == &t.id && typ == "task") {
|
||||||
|
tasks.push(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for s in self.state.snippets.read() {
|
||||||
|
if matches.iter().any(|(id, typ)| id == &s.name && typ == "snippet") {
|
||||||
|
snippets.push(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for a in self.state.adrs.read() {
|
||||||
|
if matches.iter().any(|(id, typ)| id == &a.id && typ == "adr") {
|
||||||
|
adrs.push(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let q = req.query.to_lowercase();
|
let q = req.query.to_lowercase();
|
||||||
|
|
||||||
let mut kg = self.state.get_full_graph();
|
|
||||||
kg.entities.retain(|name, e| {
|
|
||||||
(req.namespace.is_none() || e.namespace == *req.namespace.as_ref().unwrap())
|
|
||||||
&& (name.to_lowercase().contains(&q)
|
|
||||||
|| e.entity_type.to_lowercase().contains(&q)
|
|
||||||
|| e.observations.join(" ").to_lowercase().contains(&q))
|
|
||||||
});
|
|
||||||
|
|
||||||
let tasks: Vec<_> = self
|
|
||||||
.state
|
|
||||||
.tasks
|
|
||||||
.read()
|
|
||||||
.into_iter()
|
|
||||||
.filter(|t| {
|
|
||||||
t.title.to_lowercase().contains(&q)
|
|
||||||
|| t.description.to_lowercase().contains(&q)
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
let snippets: Vec<_> = self
|
|
||||||
.state
|
|
||||||
.snippets
|
|
||||||
.read()
|
|
||||||
.into_iter()
|
|
||||||
.filter(|s| {
|
|
||||||
s.name.to_lowercase().contains(&q)
|
|
||||||
|| s.description.to_lowercase().contains(&q)
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
let adrs: Vec<_> = self
|
|
||||||
.state
|
|
||||||
.adrs
|
|
||||||
.read()
|
|
||||||
.into_iter()
|
|
||||||
.filter(|a| {
|
|
||||||
a.title.to_lowercase().contains(&q)
|
|
||||||
|| a.context.to_lowercase().contains(&q)
|
|
||||||
|| a.decision.to_lowercase().contains(&q)
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
let tech_debts: Vec<_> = self
|
let tech_debts: Vec<_> = self
|
||||||
.state
|
.state
|
||||||
.tech_debts
|
.tech_debts
|
||||||
|
|||||||
+35
-1
@@ -3,6 +3,7 @@ mod models;
|
|||||||
mod state;
|
mod state;
|
||||||
mod store;
|
mod store;
|
||||||
mod tools;
|
mod tools;
|
||||||
|
mod search;
|
||||||
|
|
||||||
use crate::handlers::MemoryHandler;
|
use crate::handlers::MemoryHandler;
|
||||||
use crate::models::*;
|
use crate::models::*;
|
||||||
@@ -84,6 +85,7 @@ async fn reconcile_worker(state: Arc<MemoryState>) {
|
|||||||
let has_files = glob::glob(&pattern).map(|p| p.count() > 0).unwrap_or(false);
|
let has_files = glob::glob(&pattern).map(|p| p.count() > 0).unwrap_or(false);
|
||||||
if has_local || has_files {
|
if has_local || has_files {
|
||||||
state.apply_sync_write(|_master| {});
|
state.apply_sync_write(|_master| {});
|
||||||
|
state.rebuild_index();
|
||||||
}
|
}
|
||||||
|
|
||||||
let now = SystemTime::now()
|
let now = SystemTime::now()
|
||||||
@@ -152,6 +154,35 @@ fn run_server(state: Arc<MemoryState>) -> SdkResult<()> {
|
|||||||
axum::routing::get(|| async move {
|
axum::routing::get(|| async move {
|
||||||
axum::http::StatusCode::OK
|
axum::http::StatusCode::OK
|
||||||
}),
|
}),
|
||||||
|
).with_route(
|
||||||
|
"/dashboard",
|
||||||
|
axum::routing::get(|| async move {
|
||||||
|
axum::response::Html(include_str!("dashboard.html"))
|
||||||
|
}),
|
||||||
|
).with_route(
|
||||||
|
"/api/stats",
|
||||||
|
axum::routing::get({
|
||||||
|
let state_clone = state.clone();
|
||||||
|
move || async move {
|
||||||
|
let (entities, relations) = {
|
||||||
|
let graph = state_clone.get_full_graph();
|
||||||
|
(graph.entities.len(), graph.relations.len())
|
||||||
|
};
|
||||||
|
let tasks = state_clone.tasks.read().len();
|
||||||
|
let snippets = state_clone.snippets.read().len();
|
||||||
|
let tech_debts = state_clone.tech_debts.read().len();
|
||||||
|
let adrs = state_clone.adrs.read().len();
|
||||||
|
|
||||||
|
axum::Json(serde_json::json!({
|
||||||
|
"entities": entities,
|
||||||
|
"relations": relations,
|
||||||
|
"tasks": tasks,
|
||||||
|
"snippets": snippets,
|
||||||
|
"tech_debts": tech_debts,
|
||||||
|
"adrs": adrs
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
println!("MCP Memory Server running on http://0.0.0.0:3000/sse");
|
println!("MCP Memory Server running on http://0.0.0.0:3000/sse");
|
||||||
@@ -190,7 +221,7 @@ fn main() -> SdkResult<()> {
|
|||||||
{
|
{
|
||||||
// This shouldn't be executed on linux natively anymore due to workspace split,
|
// This shouldn't be executed on linux natively anymore due to workspace split,
|
||||||
// but keeping it as a fallback.
|
// but keeping it as a fallback.
|
||||||
let target_url = cli.target.as_deref().unwrap_or("http://host.docker.internal:3000");
|
let target_url = cli.target.as_deref().unwrap_or("http://127.0.0.1:3000");
|
||||||
let _ = proxy::run_proxy(target_url);
|
let _ = proxy::run_proxy(target_url);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
@@ -211,6 +242,7 @@ fn main() -> SdkResult<()> {
|
|||||||
session_graph: RwLock::new(KnowledgeGraph::default()),
|
session_graph: RwLock::new(KnowledgeGraph::default()),
|
||||||
base_dir: base.clone(),
|
base_dir: base.clone(),
|
||||||
master_cache: RwLock::new((KnowledgeGraph::default(), SystemTime::UNIX_EPOCH)),
|
master_cache: RwLock::new((KnowledgeGraph::default(), SystemTime::UNIX_EPOCH)),
|
||||||
|
search_index: RwLock::new(crate::search::MemoryIndex::new().unwrap()),
|
||||||
ledger: Store::new(base.join("audit_ledger.json")),
|
ledger: Store::new(base.join("audit_ledger.json")),
|
||||||
sticky: Store::new(base.join("sticky_notes.json")),
|
sticky: Store::new(base.join("sticky_notes.json")),
|
||||||
tasks: Store::new(base.join("tasks.json")),
|
tasks: Store::new(base.join("tasks.json")),
|
||||||
@@ -231,6 +263,8 @@ fn main() -> SdkResult<()> {
|
|||||||
context_workspaces: Store::new(base.join("context_workspaces.json")),
|
context_workspaces: Store::new(base.join("context_workspaces.json")),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
state.rebuild_index();
|
||||||
|
|
||||||
if let Some(command) = cli.command {
|
if let Some(command) = cli.command {
|
||||||
match command {
|
match command {
|
||||||
Commands::Gate { subcmd } => {
|
Commands::Gate { subcmd } => {
|
||||||
|
|||||||
+36
-6
@@ -1,7 +1,7 @@
|
|||||||
use tantivy::schema::*;
|
use tantivy::schema::*;
|
||||||
use tantivy::{doc, Index, IndexWriter, IndexReader, ReloadPolicy};
|
use tantivy::{doc, Index, IndexWriter, IndexReader, ReloadPolicy};
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
use crate::models::{Entity, Task, StickyNote, Adr, Snippet};
|
use crate::models::{Entity, Task, Adr, Snippet};
|
||||||
|
|
||||||
pub struct MemoryIndex {
|
pub struct MemoryIndex {
|
||||||
index: Index,
|
index: Index,
|
||||||
@@ -71,21 +71,51 @@ impl MemoryIndex {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn search(&self, query: &str, namespace: Option<&str>) -> tantivy::Result<Vec<String>> {
|
pub fn search(&self, query: &str, namespace: Option<&str>) -> tantivy::Result<Vec<(String, String)>> {
|
||||||
let searcher = self.reader.searcher();
|
let searcher = self.reader.searcher();
|
||||||
let query_parser = tantivy::query::QueryParser::for_index(&self.index, vec![self.title_field, self.body_field]);
|
let query_parser = tantivy::query::QueryParser::for_index(&self.index, vec![self.title_field, self.body_field]);
|
||||||
let q = query_parser.parse_query(query)?;
|
let q = query_parser.parse_query(query)?;
|
||||||
|
|
||||||
let top_docs = searcher.search(&q, &tantivy::collector::TopDocs::with_limit(50))?;
|
let top_docs = searcher.search(&q, &tantivy::collector::TopDocs::with_limit(50).order_by_score())?;
|
||||||
let mut results = Vec::new();
|
let mut results = Vec::new();
|
||||||
for (_score, doc_address) in top_docs {
|
for (_score, doc_address) in top_docs {
|
||||||
let retrieved_doc = searcher.doc::<tantivy::TantivyDocument>(doc_address)?;
|
let retrieved_doc = searcher.doc::<tantivy::TantivyDocument>(doc_address)?;
|
||||||
if let Some(val) = retrieved_doc.get_first(self.title_field) {
|
let id = retrieved_doc.get_first(self.id_field).and_then(|v| v.as_str()).unwrap_or("").to_string();
|
||||||
if let Some(t) = val.as_str() {
|
let doc_type = retrieved_doc.get_first(self.type_field).and_then(|v| v.as_str()).unwrap_or("").to_string();
|
||||||
results.push(t.to_string());
|
let doc_ns = retrieved_doc.get_first(self.namespace_field).and_then(|v| v.as_str()).unwrap_or("");
|
||||||
|
if let Some(ns) = namespace {
|
||||||
|
if doc_ns != ns && doc_ns != "global" {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
results.push((id, doc_type));
|
||||||
}
|
}
|
||||||
Ok(results)
|
Ok(results)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn index_snippet(&self, s: &Snippet) -> tantivy::Result<()> {
|
||||||
|
let mut writer = self.writer.lock().unwrap();
|
||||||
|
writer.add_document(doc!(
|
||||||
|
self.id_field => s.name.clone(),
|
||||||
|
self.title_field => s.name.clone(),
|
||||||
|
self.body_field => format!("{} {}", s.language, s.description),
|
||||||
|
self.type_field => "snippet",
|
||||||
|
self.namespace_field => "global"
|
||||||
|
))?;
|
||||||
|
writer.commit()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn index_adr(&self, a: &Adr) -> tantivy::Result<()> {
|
||||||
|
let mut writer = self.writer.lock().unwrap();
|
||||||
|
writer.add_document(doc!(
|
||||||
|
self.id_field => a.id.clone(),
|
||||||
|
self.title_field => a.title.clone(),
|
||||||
|
self.body_field => format!("{} {} {}", a.context, a.decision, a.consequence),
|
||||||
|
self.type_field => "adr",
|
||||||
|
self.namespace_field => "global"
|
||||||
|
))?;
|
||||||
|
writer.commit()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
use crate::models::*;
|
use crate::models::*;
|
||||||
use crate::store::{Store, read_json_file, write_json_atomic};
|
use crate::store::{Store, read_json_file, write_json_atomic};
|
||||||
|
use crate::search::MemoryIndex;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
@@ -11,6 +12,7 @@ pub struct MemoryState {
|
|||||||
pub master_path: PathBuf,
|
pub master_path: PathBuf,
|
||||||
pub session_graph: RwLock<KnowledgeGraph>,
|
pub session_graph: RwLock<KnowledgeGraph>,
|
||||||
pub master_cache: RwLock<(KnowledgeGraph, SystemTime)>,
|
pub master_cache: RwLock<(KnowledgeGraph, SystemTime)>,
|
||||||
|
pub search_index: RwLock<MemoryIndex>,
|
||||||
pub ledger: Store<Vec<CodeChange>>,
|
pub ledger: Store<Vec<CodeChange>>,
|
||||||
pub sticky: Store<Vec<StickyNote>>,
|
pub sticky: Store<Vec<StickyNote>>,
|
||||||
pub tasks: Store<Vec<Task>>,
|
pub tasks: Store<Vec<Task>>,
|
||||||
@@ -136,5 +138,27 @@ impl MemoryState {
|
|||||||
|
|
||||||
let _ = fs::remove_file(&lock_path);
|
let _ = fs::remove_file(&lock_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn rebuild_index(&self) {
|
||||||
|
if let Ok(new_idx) = MemoryIndex::new() {
|
||||||
|
let full = self.get_full_graph();
|
||||||
|
for (_, e) in &full.entities {
|
||||||
|
let _ = new_idx.index_entity(e);
|
||||||
|
}
|
||||||
|
for t in self.tasks.read() {
|
||||||
|
let _ = new_idx.index_task(&t);
|
||||||
|
}
|
||||||
|
for s in self.snippets.read() {
|
||||||
|
let _ = new_idx.index_snippet(&s);
|
||||||
|
}
|
||||||
|
for a in self.adrs.read() {
|
||||||
|
let _ = new_idx.index_adr(&a);
|
||||||
|
}
|
||||||
|
if let Ok(mut w) = self.search_index.write() {
|
||||||
|
*w = new_idx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Reference in new issue
Block a user