diff --git a/Cargo.lock b/Cargo.lock index c8413cb..a7dfe95 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -50,98 +50,6 @@ dependencies = [ "core_extensions", ] -[[package]] -name = "adler2" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" - -[[package]] -name = "ahash" -version = "0.8.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" -dependencies = [ - "cfg-if", - "once_cell", - "version_check", - "zerocopy", -] - -[[package]] -name = "aho-corasick" -version = "1.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" -dependencies = [ - "memchr", -] - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - -[[package]] -name = "anstream" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "is_terminal_polyfill", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" - -[[package]] -name = "anstyle-parse" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" -dependencies = [ - "windows-sys 0.61.2", -] - -[[package]] -name = "anstyle-wincon" -version = "3.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" -dependencies = [ - "anstyle", - "once_cell_polyfill", - "windows-sys 0.61.2", -] - -[[package]] -name = "anyhow" -version = "1.0.102" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" - [[package]] name = "as_derive_utils" version = "0.11.0" @@ -154,30 +62,12 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "async-compression" -version = "0.4.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0f9ee0f6e02ffd7ad5816e9464499fba7b3effd01123b515c41d1697c43dad1" -dependencies = [ - "compression-codecs", - "compression-core", - "pin-project-lite", - "tokio", -] - [[package]] name = "atomic-waker" version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" -[[package]] -name = "autocfg" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" - [[package]] name = "aws-lc-rs" version = "1.16.2" @@ -212,16 +102,6 @@ version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" -[[package]] -name = "bstr" -version = "1.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab" -dependencies = [ - "memchr", - "serde", -] - [[package]] name = "bumpalo" version = "3.20.2" @@ -264,19 +144,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" -[[package]] -name = "chrono" -version = "0.4.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" -dependencies = [ - "iana-time-zone", - "js-sys", - "num-traits", - "wasm-bindgen", - "windows-link", -] - [[package]] name = "cmake" version = "0.1.57" @@ -286,22 +153,6 @@ dependencies = [ "cc", ] -[[package]] -name = "codespan-reporting" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" -dependencies = [ - "termcolor", - "unicode-width", -] - -[[package]] -name = "colorchoice" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" - [[package]] name = "combine" version = "4.6.7" @@ -312,23 +163,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "compression-codecs" -version = "0.4.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb7b51a7d9c967fc26773061ba86150f19c50c0d65c887cb1fbe295fd16619b7" -dependencies = [ - "compression-core", - "flate2", - "memchr", -] - -[[package]] -name = "compression-core" -version = "0.4.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75984efb6ed102a0d42db99afb6c1948f0380d1d91808d5529916e6c08b49d8d" - [[package]] name = "const_panic" version = "0.2.15" @@ -379,21 +213,6 @@ version = "1.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "533d38ecd2709b7608fb8e18e4504deb99e9a72879e6aa66373a76d8dc4259ea" -[[package]] -name = "crc32fast" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "critical-section" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" - [[package]] name = "crossbeam-channel" version = "0.5.15" @@ -447,12 +266,6 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" -[[package]] -name = "either" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" - [[package]] name = "encoding_rs" version = "0.8.35" @@ -462,56 +275,12 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "env_filter" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32e90c2accc4b07a8456ea0debdc2e7587bdd890680d71173a15d4ae604f6eef" -dependencies = [ - "log", - "regex", -] - -[[package]] -name = "env_logger" -version = "0.11.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0621c04f2196ac3f488dd583365b9c09be011a4ab8b9f37248ffcc8f6198b56a" -dependencies = [ - "anstream", - "anstyle", - "env_filter", - "jiff", - "log", -] - [[package]] name = "equivalent" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" -[[package]] -name = "erased-serde" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2add8a07dd6a8d93ff627029c51de145e12686fbc36ecb298ac22e74cf02dec" -dependencies = [ - "serde", - "serde_core", - "typeid", -] - -[[package]] -name = "errno" -version = "0.3.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" -dependencies = [ - "libc", - "windows-sys 0.61.2", -] - [[package]] name = "fallible-iterator" version = "0.3.0" @@ -524,40 +293,18 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" -[[package]] -name = "fastrand" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" - [[package]] name = "find-msvc-tools" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" -[[package]] -name = "flate2" -version = "1.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" -dependencies = [ - "crc32fast", - "miniz_oxide", -] - [[package]] name = "fnv" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" -[[package]] -name = "foldhash" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" - [[package]] name = "foldhash" version = "0.2.0" @@ -637,21 +384,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "generator" -version = "0.8.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52f04ae4152da20c76fe800fa48659201d5cf627c5149ca0b707b69d7eef6cf9" -dependencies = [ - "cc", - "cfg-if", - "libc", - "log", - "rustversion", - "windows-link", - "windows-result", -] - [[package]] name = "getrandom" version = "0.2.17" @@ -674,24 +406,11 @@ dependencies = [ "cfg-if", "js-sys", "libc", - "r-efi 5.3.0", + "r-efi", "wasip2", "wasm-bindgen", ] -[[package]] -name = "getrandom" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" -dependencies = [ - "cfg-if", - "libc", - "r-efi 6.0.0", - "wasip2", - "wasip3", -] - [[package]] name = "h2" version = "0.4.13" @@ -711,22 +430,13 @@ dependencies = [ "tracing", ] -[[package]] -name = "hashbrown" -version = "0.15.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" -dependencies = [ - "foldhash 0.1.5", -] - [[package]] name = "hashbrown" version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" dependencies = [ - "foldhash 0.2.0", + "foldhash", ] [[package]] @@ -735,15 +445,9 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea0b22561a9c04a7cb1a302c013e0259cd3b4bb619f145b32f72b8b4bcbed230" dependencies = [ - "hashbrown 0.16.1", + "hashbrown", ] -[[package]] -name = "heck" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - [[package]] name = "http" version = "1.4.0" @@ -819,7 +523,6 @@ dependencies = [ "tokio", "tokio-rustls", "tower-service", - "webpki-roots", ] [[package]] @@ -847,30 +550,6 @@ dependencies = [ "windows-registry", ] -[[package]] -name = "iana-time-zone" -version = "0.1.65" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "log", - "wasm-bindgen", - "windows-core", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] - [[package]] name = "icu_collections" version = "2.1.1" @@ -952,12 +631,6 @@ dependencies = [ "zerovec", ] -[[package]] -name = "id-arena" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" - [[package]] name = "idna" version = "1.1.0" @@ -986,9 +659,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" dependencies = [ "equivalent", - "hashbrown 0.16.1", - "serde", - "serde_core", + "hashbrown", ] [[package]] @@ -1007,42 +678,12 @@ dependencies = [ "serde", ] -[[package]] -name = "is_terminal_polyfill" -version = "1.70.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" - [[package]] name = "itoa" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" -[[package]] -name = "jiff" -version = "0.2.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a3546dc96b6d42c5f24902af9e2538e82e39ad350b0c766eb3fbf2d8f3d8359" -dependencies = [ - "jiff-static", - "log", - "portable-atomic", - "portable-atomic-util", - "serde_core", -] - -[[package]] -name = "jiff-static" -version = "0.2.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a8c8b344124222efd714b73bb41f8b5120b27a7cc1c75593a6ff768d9d05aa4" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - [[package]] name = "jni" version = "0.21.1" @@ -1107,18 +748,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" - -[[package]] -name = "leb128fmt" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" - [[package]] name = "libc" version = "0.2.183" @@ -1155,12 +784,6 @@ dependencies = [ "vcpkg", ] -[[package]] -name = "linux-raw-sys" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" - [[package]] name = "litemap" version = "0.8.1" @@ -1182,53 +805,12 @@ version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" -[[package]] -name = "loom" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "419e0dc8046cb947daa77eb95ae174acfbddb7673b4151f56d1eed8e93fbfaca" -dependencies = [ - "cfg-if", - "generator", - "scoped-tls", - "tracing", - "tracing-subscriber", -] - [[package]] name = "lru-slab" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" -[[package]] -name = "lua-src" -version = "550.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e836dc8ae16806c9bdcf42003a88da27d163433e3f9684c52f0301258004a4fb" -dependencies = [ - "cc", -] - -[[package]] -name = "luajit-src" -version = "210.6.6+707c12b" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a86cc925d4053d0526ae7f5bc765dbd0d7a5d1a63d43974f4966cb349ca63295" -dependencies = [ - "cc", - "which", -] - -[[package]] -name = "matchers" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" -dependencies = [ - "regex-automata", -] - [[package]] name = "memchr" version = "2.8.0" @@ -1251,16 +833,6 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" -[[package]] -name = "miniz_oxide" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" -dependencies = [ - "adler2", - "simd-adler32", -] - [[package]] name = "mio" version = "1.1.1" @@ -1272,183 +844,17 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "mlua" -version = "0.11.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccd36acfa49ce6ee56d1307a061dd302c564eee757e6e4cd67eb4f7204846fab" -dependencies = [ - "bstr", - "either", - "erased-serde", - "libc", - "mlua-sys", - "num-traits", - "parking_lot", - "rustc-hash", - "rustversion", - "serde", - "serde-value", -] - -[[package]] -name = "mlua-sys" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f1c3a7fc7580227ece249fd90aa2fa3b39eb2b49d3aec5e103b3e85f2c3dfc8" -dependencies = [ - "cc", - "cfg-if", - "libc", - "lua-src", - "luajit-src", - "pkg-config", -] - -[[package]] -name = "musli" -version = "0.0.124" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b310b280353d9e1c92861820321f8742b02666acaf984a29cd8946965444384" -dependencies = [ - "loom", - "musli-core", - "serde", - "simdutf8", -] - -[[package]] -name = "musli-core" -version = "0.0.124" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d00e227a374e92550ce2eb5002ae116e02a43926d7243c95997138406ae4e157" -dependencies = [ - "musli-macros", -] - -[[package]] -name = "musli-macros" -version = "0.0.124" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7427c9aa85c882cd4dbe712d2fcdc511db05d595f7787e6747c90cd7d67efc4" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "nanorand" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3" -dependencies = [ - "getrandom 0.2.17", -] - [[package]] name = "nom" version = "1.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a5b8c256fd9471521bcb84c3cdba98921497f1a331cbc15b8030fc63b82050ce" -[[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]] -name = "num" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" -dependencies = [ - "num-bigint", - "num-complex", - "num-integer", - "num-iter", - "num-rational", - "num-traits", -] - -[[package]] -name = "num-bigint" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" -dependencies = [ - "num-integer", - "num-traits", -] - -[[package]] -name = "num-complex" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-integer" -version = "0.1.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-iter" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-rational" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" -dependencies = [ - "num-bigint", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", -] - [[package]] name = "once_cell" version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" -dependencies = [ - "critical-section", - "portable-atomic", -] - -[[package]] -name = "once_cell_polyfill" -version = "1.70.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" [[package]] name = "openssl-probe" @@ -1462,33 +868,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" -[[package]] -name = "ordered-float" -version = "2.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c" -dependencies = [ - "num-traits", -] - -[[package]] -name = "owlry-lua" -version = "0.4.10" -dependencies = [ - "abi_stable", - "chrono", - "dirs", - "meval", - "mlua", - "owlry-plugin-api", - "reqwest 0.13.2", - "semver", - "serde", - "serde_json", - "tempfile", - "toml", -] - [[package]] name = "owlry-plugin-api" version = "0.4.10" @@ -1604,7 +983,7 @@ dependencies = [ "abi_stable", "dirs", "owlry-plugin-api", - "reqwest 0.13.2", + "reqwest", "serde", "serde_json", "toml", @@ -1618,25 +997,6 @@ dependencies = [ "owlry-plugin-api", ] -[[package]] -name = "owlry-rune" -version = "0.4.10" -dependencies = [ - "chrono", - "dirs", - "env_logger", - "log", - "owlry-plugin-api", - "reqwest 0.13.2", - "rune", - "rune-modules", - "semver", - "serde", - "serde_json", - "tempfile", - "toml", -] - [[package]] name = "parking_lot" version = "0.12.5" @@ -1672,26 +1032,6 @@ version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" -[[package]] -name = "pin-project" -version = "1.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1749c7ed4bcaf4c3d0a3efc28538844fb29bcdd7d2b67b2be7e20ba861ff517" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b20ed30f105399776b9c883e68e536ef602a16ae6f596d2c473591d6ad64c6" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - [[package]] name = "pin-project-lite" version = "0.2.17" @@ -1710,21 +1050,6 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" -[[package]] -name = "portable-atomic" -version = "1.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" - -[[package]] -name = "portable-atomic-util" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "091397be61a01d4be58e7841595bd4bfedb15f1cd54977d79b8271e94ed799a3" -dependencies = [ - "portable-atomic", -] - [[package]] name = "potential_utf" version = "0.1.4" @@ -1743,16 +1068,6 @@ dependencies = [ "zerocopy", ] -[[package]] -name = "prettyplease" -version = "0.2.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" -dependencies = [ - "proc-macro2", - "syn 2.0.117", -] - [[package]] name = "proc-macro2" version = "1.0.106" @@ -1833,12 +1148,6 @@ version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" -[[package]] -name = "r-efi" -version = "6.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" - [[package]] name = "rand" version = "0.9.2" @@ -1888,35 +1197,6 @@ dependencies = [ "thiserror 1.0.69", ] -[[package]] -name = "regex" -version = "1.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" - [[package]] name = "repr_offset" version = "0.2.2" @@ -1926,44 +1206,6 @@ dependencies = [ "tstr", ] -[[package]] -name = "reqwest" -version = "0.12.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" -dependencies = [ - "base64", - "bytes", - "futures-core", - "http", - "http-body", - "http-body-util", - "hyper", - "hyper-rustls", - "hyper-util", - "js-sys", - "log", - "percent-encoding", - "pin-project-lite", - "quinn", - "rustls", - "rustls-pki-types", - "serde", - "serde_json", - "serde_urlencoded", - "sync_wrapper", - "tokio", - "tokio-rustls", - "tower", - "tower-http", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "webpki-roots", -] - [[package]] name = "reqwest" version = "0.13.2" @@ -2026,118 +1268,10 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8a1f2315036ef6b1fbacd1972e8ee7688030b0a2121edfc2a6550febd41574d" dependencies = [ - "hashbrown 0.16.1", + "hashbrown", "thiserror 2.0.18", ] -[[package]] -name = "rune" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7b9174512d64882469ea9b12876305680154a541be448dcdc56f58acacbc3e0" -dependencies = [ - "anyhow", - "codespan-reporting", - "futures-core", - "futures-util", - "itoa", - "memchr", - "musli", - "num", - "once_cell", - "pin-project", - "rune-alloc", - "rune-core", - "rune-macros", - "rune-tracing", - "ryu", - "serde", - "syntree", - "unicode-ident", -] - -[[package]] -name = "rune-alloc" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f12484a608c8907b9a4590f11b669263e960d1fd40f3d3c992c6f15eec931ae9" -dependencies = [ - "ahash", - "pin-project", - "rune-alloc-macros", - "serde", -] - -[[package]] -name = "rune-alloc-macros" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "382b14f6d8e65e9cfec789e85125f3e1d758b2756705739e39ccf06fd249a564" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "rune-core" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c424b28fde0f5012680361662145f238f04aeac8a320f352a6e2de863709e7b3" -dependencies = [ - "musli", - "rune-alloc", - "serde", - "twox-hash", -] - -[[package]] -name = "rune-macros" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c86600b36281adeb101c2e4f0be325752fa4c07431e9234e05be5678ad9a97f7" -dependencies = [ - "proc-macro2", - "quote", - "rune-core", - "syn 2.0.117", -] - -[[package]] -name = "rune-modules" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f4ef5dc3546042989f4abc70d6b9f707a539d5cbb5cb2fb167f8fbe891e1b64" -dependencies = [ - "base64", - "nanorand", - "reqwest 0.12.28", - "rune", - "serde_json", - "tokio", - "toml", -] - -[[package]] -name = "rune-tracing" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0717a7c726015688a19ebfa4bea03a20d2acdd96eeacb5ef48f4ec780e11ac4b" -dependencies = [ - "rune-tracing-macros", -] - -[[package]] -name = "rune-tracing-macros" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12387f96a3e131ce5be8c5668e55f1581dbc6635555d77aa07ab509fd13562bb" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - [[package]] name = "rusqlite" version = "0.39.0" @@ -2168,19 +1302,6 @@ dependencies = [ "semver", ] -[[package]] -name = "rustix" -version = "1.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" -dependencies = [ - "bitflags", - "errno", - "libc", - "linux-raw-sys", - "windows-sys 0.61.2", -] - [[package]] name = "rustls" version = "0.23.37" @@ -2189,7 +1310,6 @@ checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4" dependencies = [ "aws-lc-rs", "once_cell", - "ring", "rustls-pki-types", "rustls-webpki", "subtle", @@ -2263,12 +1383,6 @@ version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" -[[package]] -name = "ryu" -version = "1.0.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" - [[package]] name = "same-file" version = "1.0.6" @@ -2287,12 +1401,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "scoped-tls" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" - [[package]] name = "scopeguard" version = "1.2.0" @@ -2338,16 +1446,6 @@ dependencies = [ "serde_derive", ] -[[package]] -name = "serde-value" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" -dependencies = [ - "ordered-float", - "serde", -] - [[package]] name = "serde_core" version = "1.0.228" @@ -2390,55 +1488,12 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_urlencoded" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" -dependencies = [ - "form_urlencoded", - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "sharded-slab" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" -dependencies = [ - "lazy_static", -] - [[package]] name = "shlex" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" -[[package]] -name = "signal-hook-registry" -version = "1.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" -dependencies = [ - "errno", - "libc", -] - -[[package]] -name = "simd-adler32" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" - -[[package]] -name = "simdutf8" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" - [[package]] name = "slab" version = "0.4.12" @@ -2527,12 +1582,6 @@ dependencies = [ "syn 2.0.117", ] -[[package]] -name = "syntree" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00c99c9cda412afe293a6b962af651b4594161ba88c1affe7ef66459ea040a06" - [[package]] name = "system-configuration" version = "0.7.0" @@ -2554,28 +1603,6 @@ dependencies = [ "libc", ] -[[package]] -name = "tempfile" -version = "3.27.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" -dependencies = [ - "fastrand", - "getrandom 0.4.2", - "once_cell", - "rustix", - "windows-sys 0.61.2", -] - -[[package]] -name = "termcolor" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" -dependencies = [ - "winapi-util", -] - [[package]] name = "thiserror" version = "1.0.69" @@ -2616,15 +1643,6 @@ dependencies = [ "syn 2.0.117", ] -[[package]] -name = "thread_local" -version = "1.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" -dependencies = [ - "cfg-if", -] - [[package]] name = "tinystr" version = "0.8.2" @@ -2660,7 +1678,6 @@ dependencies = [ "libc", "mio", "pin-project-lite", - "signal-hook-registry", "socket2", "windows-sys 0.61.2", ] @@ -2750,18 +1767,13 @@ version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" dependencies = [ - "async-compression", "bitflags", "bytes", - "futures-core", "futures-util", "http", "http-body", - "http-body-util", "iri-string", "pin-project-lite", - "tokio", - "tokio-util", "tower", "tower-layer", "tower-service", @@ -2796,36 +1808,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" dependencies = [ "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 = [ - "matchers", - "nu-ansi-term", - "once_cell", - "regex-automata", - "sharded-slab", - "smallvec", - "thread_local", - "tracing", - "tracing-core", - "tracing-log", ] [[package]] @@ -2849,24 +1831,12 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e78122066b0cb818b8afd08f7ed22f7fdbc3e90815035726f0840d0d26c0747a" -[[package]] -name = "twox-hash" -version = "2.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ea3136b675547379c4bd395ca6b938e5ad3c3d20fad76e7fe85f9e0d011419c" - [[package]] name = "typed-arena" version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" -[[package]] -name = "typeid" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" - [[package]] name = "typewit" version = "1.14.2" @@ -2879,18 +1849,6 @@ version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" -[[package]] -name = "unicode-width" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" - -[[package]] -name = "unicode-xid" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" - [[package]] name = "untrusted" version = "0.9.0" @@ -2915,30 +1873,12 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" -[[package]] -name = "utf8parse" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" - -[[package]] -name = "valuable" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" - [[package]] name = "vcpkg" version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" -[[package]] -name = "version_check" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" - [[package]] name = "walkdir" version = "2.5.0" @@ -2973,15 +1913,6 @@ dependencies = [ "wit-bindgen", ] -[[package]] -name = "wasip3" -version = "0.4.0+wasi-0.3.0-rc-2026-01-06" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" -dependencies = [ - "wit-bindgen", -] - [[package]] name = "wasm-bindgen" version = "0.2.114" @@ -3041,40 +1972,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "wasm-encoder" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" -dependencies = [ - "leb128fmt", - "wasmparser", -] - -[[package]] -name = "wasm-metadata" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" -dependencies = [ - "anyhow", - "indexmap", - "wasm-encoder", - "wasmparser", -] - -[[package]] -name = "wasmparser" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" -dependencies = [ - "bitflags", - "hashbrown 0.15.5", - "indexmap", - "semver", -] - [[package]] name = "web-sys" version = "0.3.91" @@ -3104,24 +2001,6 @@ dependencies = [ "rustls-pki-types", ] -[[package]] -name = "webpki-roots" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cfaf3c063993ff62e73cb4311efde4db1efb31ab78a3e5c457939ad5cc0bed" -dependencies = [ - "rustls-pki-types", -] - -[[package]] -name = "which" -version = "8.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81995fafaaaf6ae47a7d0cc83c67caf92aeb7e5331650ae6ff856f7c0c60c459" -dependencies = [ - "libc", -] - [[package]] name = "winapi" version = "0.3.9" @@ -3153,41 +2032,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows-core" -version = "0.62.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" -dependencies = [ - "windows-implement", - "windows-interface", - "windows-link", - "windows-result", - "windows-strings", -] - -[[package]] -name = "windows-implement" -version = "0.60.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "windows-interface" -version = "0.59.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - [[package]] name = "windows-link" version = "0.2.1" @@ -3525,88 +2369,6 @@ name = "wit-bindgen" version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" -dependencies = [ - "wit-bindgen-rust-macro", -] - -[[package]] -name = "wit-bindgen-core" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" -dependencies = [ - "anyhow", - "heck", - "wit-parser", -] - -[[package]] -name = "wit-bindgen-rust" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" -dependencies = [ - "anyhow", - "heck", - "indexmap", - "prettyplease", - "syn 2.0.117", - "wasm-metadata", - "wit-bindgen-core", - "wit-component", -] - -[[package]] -name = "wit-bindgen-rust-macro" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" -dependencies = [ - "anyhow", - "prettyplease", - "proc-macro2", - "quote", - "syn 2.0.117", - "wit-bindgen-core", - "wit-bindgen-rust", -] - -[[package]] -name = "wit-component" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" -dependencies = [ - "anyhow", - "bitflags", - "indexmap", - "log", - "serde", - "serde_derive", - "serde_json", - "wasm-encoder", - "wasm-metadata", - "wasmparser", - "wit-parser", -] - -[[package]] -name = "wit-parser" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" -dependencies = [ - "anyhow", - "id-arena", - "indexmap", - "log", - "semver", - "serde", - "serde_derive", - "serde_json", - "unicode-xid", - "wasmparser", -] [[package]] name = "writeable" diff --git a/Cargo.toml b/Cargo.toml index 58e638d..cf70406 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,8 +13,6 @@ members = [ "crates/owlry-plugin-systemd", "crates/owlry-plugin-weather", "crates/owlry-plugin-websearch", - "crates/owlry-lua", - "crates/owlry-rune", ] resolver = "2" diff --git a/aur/owlry-lua/.SRCINFO b/aur/owlry-lua/.SRCINFO deleted file mode 100644 index 9075633..0000000 --- a/aur/owlry-lua/.SRCINFO +++ /dev/null @@ -1,13 +0,0 @@ -pkgbase = owlry-lua - pkgdesc = Lua runtime for Owlry - enables loading user-created Lua plugins - pkgver = 0.4.10 - pkgrel = 1 - url = https://somegit.dev/Owlibou/owlry - arch = x86_64 - license = GPL-3.0-or-later - makedepends = cargo - depends = owlry - source = owlry-0.4.10.tar.gz::https://somegit.dev/Owlibou/owlry/archive/v0.4.10.tar.gz - b2sums = 2d3761ee892d7f283a65fa58ca6206735b1b3b6e7f764f839e8a2cbd2fee2ce446c4b992e664790439393e6cb2f21fb21abacdeaf8de9eca4514da86c608216d - -pkgname = owlry-lua diff --git a/aur/owlry-lua/PKGBUILD b/aur/owlry-lua/PKGBUILD deleted file mode 100644 index cef14ca..0000000 --- a/aur/owlry-lua/PKGBUILD +++ /dev/null @@ -1,40 +0,0 @@ -# Maintainer: vikingowl -pkgname=owlry-lua -pkgver=0.4.10 -pkgrel=1 -pkgdesc="Lua runtime for Owlry - enables loading user-created Lua plugins" -arch=('x86_64') -url="https://somegit.dev/Owlibou/owlry" -license=('GPL-3.0-or-later') -depends=('owlry') -makedepends=('cargo') -source=("owlry-$pkgver.tar.gz::$url/archive/v$pkgver.tar.gz") -b2sums=('2d3761ee892d7f283a65fa58ca6206735b1b3b6e7f764f839e8a2cbd2fee2ce446c4b992e664790439393e6cb2f21fb21abacdeaf8de9eca4514da86c608216d') - -_cratename=owlry-lua - -prepare() { - cd "owlry" - export RUSTUP_TOOLCHAIN=stable - cargo fetch --locked --target "$(rustc -vV | sed -n 's/host: //p')" -} - -build() { - cd "owlry" - export RUSTUP_TOOLCHAIN=stable - export CARGO_TARGET_DIR=target - cargo build -p $_cratename --frozen --release -} - -check() { - cd "owlry" - export RUSTUP_TOOLCHAIN=stable - export CARGO_TARGET_DIR=target - cargo test -p $_cratename --frozen --release -} - -package() { - cd "owlry" - install -Dm755 "target/release/lib${_cratename//-/_}.so" \ - "$pkgdir/usr/lib/owlry/runtimes/liblua.so" -} diff --git a/aur/owlry-rune/.SRCINFO b/aur/owlry-rune/.SRCINFO deleted file mode 100644 index 860c5d2..0000000 --- a/aur/owlry-rune/.SRCINFO +++ /dev/null @@ -1,13 +0,0 @@ -pkgbase = owlry-rune - pkgdesc = Rune runtime for Owlry - enables loading user-created Rune plugins - pkgver = 0.4.10 - pkgrel = 1 - url = https://somegit.dev/Owlibou/owlry - arch = x86_64 - license = GPL-3.0-or-later - makedepends = cargo - depends = owlry - source = owlry-0.4.10.tar.gz::https://somegit.dev/Owlibou/owlry/archive/v0.4.10.tar.gz - b2sums = 2d3761ee892d7f283a65fa58ca6206735b1b3b6e7f764f839e8a2cbd2fee2ce446c4b992e664790439393e6cb2f21fb21abacdeaf8de9eca4514da86c608216d - -pkgname = owlry-rune diff --git a/aur/owlry-rune/PKGBUILD b/aur/owlry-rune/PKGBUILD deleted file mode 100644 index e07f09d..0000000 --- a/aur/owlry-rune/PKGBUILD +++ /dev/null @@ -1,40 +0,0 @@ -# Maintainer: vikingowl -pkgname=owlry-rune -pkgver=0.4.10 -pkgrel=1 -pkgdesc="Rune runtime for Owlry - enables loading user-created Rune plugins" -arch=('x86_64') -url="https://somegit.dev/Owlibou/owlry" -license=('GPL-3.0-or-later') -depends=('owlry') -makedepends=('cargo') -source=("owlry-$pkgver.tar.gz::$url/archive/v$pkgver.tar.gz") -b2sums=('2d3761ee892d7f283a65fa58ca6206735b1b3b6e7f764f839e8a2cbd2fee2ce446c4b992e664790439393e6cb2f21fb21abacdeaf8de9eca4514da86c608216d') - -_cratename=owlry-rune - -prepare() { - cd "owlry" - export RUSTUP_TOOLCHAIN=stable - cargo fetch --locked --target "$(rustc -vV | sed -n 's/host: //p')" -} - -build() { - cd "owlry" - export RUSTUP_TOOLCHAIN=stable - export CARGO_TARGET_DIR=target - cargo build -p $_cratename --frozen --release -} - -check() { - cd "owlry" - export RUSTUP_TOOLCHAIN=stable - export CARGO_TARGET_DIR=target - cargo test -p $_cratename --frozen --release -} - -package() { - cd "owlry" - install -Dm755 "target/release/lib${_cratename//-/_}.so" \ - "$pkgdir/usr/lib/owlry/runtimes/librune.so" -} diff --git a/crates/owlry-lua/Cargo.toml b/crates/owlry-lua/Cargo.toml deleted file mode 100644 index 2227c63..0000000 --- a/crates/owlry-lua/Cargo.toml +++ /dev/null @@ -1,46 +0,0 @@ -[package] -name = "owlry-lua" -version = "0.4.10" -edition.workspace = true -rust-version.workspace = true -license.workspace = true -repository.workspace = true -description = "Lua runtime for owlry plugins - enables loading user-created Lua plugins" -keywords = ["owlry", "plugin", "lua", "runtime"] -categories = ["development-tools"] - -[lib] -crate-type = ["cdylib"] # Compile as dynamic library (.so) - -[dependencies] -# Plugin API for owlry (shared types) -owlry-plugin-api = { path = "/home/cnachtigall/ssd/git/archive/owlibou/owlry/crates/owlry-plugin-api" } - -# ABI-stable types -abi_stable = "0.11" - -# Lua runtime -mlua = { version = "0.11", features = ["lua54", "vendored", "send", "serialize"] } - -# Plugin manifest parsing -toml = "0.8" -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" - -# Version compatibility -semver = "1" - -# HTTP client for plugins -reqwest = { version = "0.13", features = ["blocking", "json"] } - -# Math expression evaluation -meval = "0.2" - -# Date/time for os.date -chrono = "0.4" - -# XDG paths -dirs = "5.0" - -[dev-dependencies] -tempfile = "3" diff --git a/crates/owlry-lua/src/api/mod.rs b/crates/owlry-lua/src/api/mod.rs deleted file mode 100644 index a85c3df..0000000 --- a/crates/owlry-lua/src/api/mod.rs +++ /dev/null @@ -1,52 +0,0 @@ -//! Lua API implementations for plugins -//! -//! This module provides the `owlry` global table and its submodules -//! that plugins can use to interact with owlry. - -mod provider; -mod utils; - -use mlua::{Lua, Result as LuaResult}; -use owlry_plugin_api::PluginItem; - -use crate::loader::ProviderRegistration; - -/// Register all owlry APIs in the Lua runtime -pub fn register_apis(lua: &Lua, plugin_dir: &std::path::Path, plugin_id: &str) -> LuaResult<()> { - let globals = lua.globals(); - - // Create the main owlry table - let owlry = lua.create_table()?; - - // Register utility APIs (log, path, fs, json) - utils::register_log_api(lua, &owlry)?; - utils::register_path_api(lua, &owlry, plugin_dir)?; - utils::register_fs_api(lua, &owlry, plugin_dir)?; - utils::register_json_api(lua, &owlry)?; - - // Register provider API - provider::register_provider_api(lua, &owlry)?; - - // Set owlry as global - globals.set("owlry", owlry)?; - - // Suppress unused warnings - let _ = plugin_id; - - Ok(()) -} - -/// Get provider registrations from the Lua runtime -pub fn get_provider_registrations(lua: &Lua) -> LuaResult> { - provider::get_registrations(lua) -} - -/// Call a provider's refresh function -pub fn call_refresh(lua: &Lua, provider_name: &str) -> LuaResult> { - provider::call_refresh(lua, provider_name) -} - -/// Call a provider's query function -pub fn call_query(lua: &Lua, provider_name: &str, query: &str) -> LuaResult> { - provider::call_query(lua, provider_name, query) -} diff --git a/crates/owlry-lua/src/api/provider.rs b/crates/owlry-lua/src/api/provider.rs deleted file mode 100644 index bf49aa3..0000000 --- a/crates/owlry-lua/src/api/provider.rs +++ /dev/null @@ -1,237 +0,0 @@ -//! Provider registration API for Lua plugins - -use mlua::{Function, Lua, Result as LuaResult, Table, Value}; -use owlry_plugin_api::PluginItem; -use std::cell::RefCell; - -use crate::loader::ProviderRegistration; - -thread_local! { - static REGISTRATIONS: RefCell> = const { RefCell::new(Vec::new()) }; -} - -/// Register the provider API in the owlry table -pub fn register_provider_api(lua: &Lua, owlry: &Table) -> LuaResult<()> { - let provider = lua.create_table()?; - - // owlry.provider.register(config) - provider.set("register", lua.create_function(register_provider)?)?; - - owlry.set("provider", provider)?; - Ok(()) -} - -/// Implementation of owlry.provider.register() -fn register_provider(_lua: &Lua, config: Table) -> LuaResult<()> { - let name: String = config.get("name")?; - let display_name: String = config.get::>("display_name")? - .unwrap_or_else(|| name.clone()); - let type_id: String = config.get::>("type_id")? - .unwrap_or_else(|| name.replace('-', "_")); - let default_icon: String = config.get::>("default_icon")? - .unwrap_or_else(|| "application-x-addon".to_string()); - let prefix: Option = config.get("prefix")?; - - // Check if it's a dynamic provider (has query function) or static (has refresh) - let has_query: bool = config.contains_key("query")?; - let has_refresh: bool = config.contains_key("refresh")?; - - if !has_query && !has_refresh { - return Err(mlua::Error::external( - "Provider must have either 'refresh' or 'query' function", - )); - } - - let is_dynamic = has_query; - - REGISTRATIONS.with(|regs| { - regs.borrow_mut().push(ProviderRegistration { - name, - display_name, - type_id, - default_icon, - prefix, - is_dynamic, - }); - }); - - Ok(()) -} - -/// Get all registered providers -pub fn get_registrations(lua: &Lua) -> LuaResult> { - // Suppress unused warning - let _ = lua; - - REGISTRATIONS.with(|regs| Ok(regs.borrow().clone())) -} - -/// Call a provider's refresh function -pub fn call_refresh(lua: &Lua, provider_name: &str) -> LuaResult> { - let globals = lua.globals(); - let owlry: Table = globals.get("owlry")?; - let provider: Table = owlry.get("provider")?; - - // Get the registered providers table (internal) - let registrations: Table = match provider.get::("_registrations")? { - Value::Table(t) => t, - _ => { - // Try to find the config directly from the global scope - // This happens when register was called with the config table - return call_provider_function(lua, provider_name, "refresh", None); - } - }; - - let config: Table = match registrations.get(provider_name)? { - Value::Table(t) => t, - _ => return Ok(Vec::new()), - }; - - let refresh_fn: Function = match config.get("refresh")? { - Value::Function(f) => f, - _ => return Ok(Vec::new()), - }; - - let result: Value = refresh_fn.call(())?; - parse_items_result(result) -} - -/// Call a provider's query function -pub fn call_query(lua: &Lua, provider_name: &str, query: &str) -> LuaResult> { - call_provider_function(lua, provider_name, "query", Some(query)) -} - -/// Call a provider function by name -fn call_provider_function( - lua: &Lua, - provider_name: &str, - function_name: &str, - query: Option<&str>, -) -> LuaResult> { - // Search through all registered providers in the Lua globals - // This is a workaround since we store registrations thread-locally - let globals = lua.globals(); - - // Try to find a registered provider with matching name - // First check if there's a _providers table - if let Ok(Value::Table(providers)) = globals.get::("_owlry_providers") - && let Ok(Value::Table(config)) = providers.get::(provider_name) - && let Ok(Value::Function(func)) = config.get::(function_name) { - let result: Value = match query { - Some(q) => func.call(q)?, - None => func.call(())?, - }; - return parse_items_result(result); - } - - // Fall back: search through globals for functions - // This is less reliable but handles simple cases - Ok(Vec::new()) -} - -/// Parse items from Lua return value -fn parse_items_result(result: Value) -> LuaResult> { - let mut items = Vec::new(); - - if let Value::Table(table) = result { - for pair in table.pairs::() { - let (_, item_table) = pair?; - if let Ok(item) = parse_item(&item_table) { - items.push(item); - } - } - } - - Ok(items) -} - -/// Parse a single item from a Lua table -fn parse_item(table: &Table) -> LuaResult { - let id: String = table.get("id")?; - let name: String = table.get("name")?; - let command: String = table.get::>("command")?.unwrap_or_default(); - let description: Option = table.get("description")?; - let icon: Option = table.get("icon")?; - let terminal: bool = table.get::>("terminal")?.unwrap_or(false); - let tags: Vec = table.get::>>("tags")?.unwrap_or_default(); - - let mut item = PluginItem::new(id, name, command); - - if let Some(desc) = description { - item = item.with_description(desc); - } - if let Some(ic) = icon { - item = item.with_icon(&ic); - } - if terminal { - item = item.with_terminal(true); - } - if !tags.is_empty() { - item = item.with_keywords(tags); - } - - Ok(item) -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::runtime::{create_lua_runtime, SandboxConfig}; - - #[test] - fn test_register_static_provider() { - let config = SandboxConfig::default(); - let lua = create_lua_runtime(&config).unwrap(); - - let owlry = lua.create_table().unwrap(); - register_provider_api(&lua, &owlry).unwrap(); - lua.globals().set("owlry", owlry).unwrap(); - - let code = r#" - owlry.provider.register({ - name = "test-provider", - display_name = "Test Provider", - refresh = function() - return { - { id = "1", name = "Item 1" } - } - end - }) - "#; - lua.load(code).set_name("test").call::<()>(()).unwrap(); - - let regs = get_registrations(&lua).unwrap(); - assert_eq!(regs.len(), 1); - assert_eq!(regs[0].name, "test-provider"); - assert!(!regs[0].is_dynamic); - } - - #[test] - fn test_register_dynamic_provider() { - let config = SandboxConfig::default(); - let lua = create_lua_runtime(&config).unwrap(); - - let owlry = lua.create_table().unwrap(); - register_provider_api(&lua, &owlry).unwrap(); - lua.globals().set("owlry", owlry).unwrap(); - - let code = r#" - owlry.provider.register({ - name = "query-provider", - prefix = "?", - query = function(q) - return { - { id = "search", name = "Search: " .. q } - } - end - }) - "#; - lua.load(code).set_name("test").call::<()>(()).unwrap(); - - let regs = get_registrations(&lua).unwrap(); - assert_eq!(regs.len(), 1); - assert_eq!(regs[0].name, "query-provider"); - assert!(regs[0].is_dynamic); - assert_eq!(regs[0].prefix, Some("?".to_string())); - } -} diff --git a/crates/owlry-lua/src/api/utils.rs b/crates/owlry-lua/src/api/utils.rs deleted file mode 100644 index 4c9058d..0000000 --- a/crates/owlry-lua/src/api/utils.rs +++ /dev/null @@ -1,370 +0,0 @@ -//! Utility APIs: logging, paths, filesystem, JSON - -use mlua::{Lua, Result as LuaResult, Table, Value}; -use std::path::{Path, PathBuf}; - -// ============================================================================ -// Logging API -// ============================================================================ - -/// Register the log API in the owlry table -pub fn register_log_api(lua: &Lua, owlry: &Table) -> LuaResult<()> { - let log = lua.create_table()?; - - log.set("debug", lua.create_function(|_, msg: String| { - eprintln!("[DEBUG] {}", msg); - Ok(()) - })?)?; - - log.set("info", lua.create_function(|_, msg: String| { - eprintln!("[INFO] {}", msg); - Ok(()) - })?)?; - - log.set("warn", lua.create_function(|_, msg: String| { - eprintln!("[WARN] {}", msg); - Ok(()) - })?)?; - - log.set("error", lua.create_function(|_, msg: String| { - eprintln!("[ERROR] {}", msg); - Ok(()) - })?)?; - - owlry.set("log", log)?; - Ok(()) -} - -// ============================================================================ -// Path API -// ============================================================================ - -/// Register the path API in the owlry table -pub fn register_path_api(lua: &Lua, owlry: &Table, plugin_dir: &Path) -> LuaResult<()> { - let path = lua.create_table()?; - - // owlry.path.config() -> ~/.config/owlry - path.set("config", lua.create_function(|_, ()| { - Ok(dirs::config_dir() - .map(|d| d.join("owlry")) - .map(|p| p.to_string_lossy().to_string()) - .unwrap_or_default()) - })?)?; - - // owlry.path.data() -> ~/.local/share/owlry - path.set("data", lua.create_function(|_, ()| { - Ok(dirs::data_dir() - .map(|d| d.join("owlry")) - .map(|p| p.to_string_lossy().to_string()) - .unwrap_or_default()) - })?)?; - - // owlry.path.cache() -> ~/.cache/owlry - path.set("cache", lua.create_function(|_, ()| { - Ok(dirs::cache_dir() - .map(|d| d.join("owlry")) - .map(|p| p.to_string_lossy().to_string()) - .unwrap_or_default()) - })?)?; - - // owlry.path.home() -> ~ - path.set("home", lua.create_function(|_, ()| { - Ok(dirs::home_dir() - .map(|p| p.to_string_lossy().to_string()) - .unwrap_or_default()) - })?)?; - - // owlry.path.join(...) -> joined path - path.set("join", lua.create_function(|_, parts: mlua::Variadic| { - let mut path = PathBuf::new(); - for part in parts { - path.push(part); - } - Ok(path.to_string_lossy().to_string()) - })?)?; - - // owlry.path.plugin_dir() -> plugin directory - let plugin_dir_str = plugin_dir.to_string_lossy().to_string(); - path.set("plugin_dir", lua.create_function(move |_, ()| { - Ok(plugin_dir_str.clone()) - })?)?; - - // owlry.path.expand(path) -> expanded path (~ -> home) - path.set("expand", lua.create_function(|_, path: String| { - if path.starts_with("~/") - && let Some(home) = dirs::home_dir() { - return Ok(home.join(&path[2..]).to_string_lossy().to_string()); - } - Ok(path) - })?)?; - - owlry.set("path", path)?; - Ok(()) -} - -// ============================================================================ -// Filesystem API -// ============================================================================ - -/// Register the fs API in the owlry table -pub fn register_fs_api(lua: &Lua, owlry: &Table, _plugin_dir: &Path) -> LuaResult<()> { - let fs = lua.create_table()?; - - // owlry.fs.exists(path) -> bool - fs.set("exists", lua.create_function(|_, path: String| { - let path = expand_path(&path); - Ok(Path::new(&path).exists()) - })?)?; - - // owlry.fs.is_dir(path) -> bool - fs.set("is_dir", lua.create_function(|_, path: String| { - let path = expand_path(&path); - Ok(Path::new(&path).is_dir()) - })?)?; - - // owlry.fs.read(path) -> string or nil - fs.set("read", lua.create_function(|_, path: String| { - let path = expand_path(&path); - match std::fs::read_to_string(&path) { - Ok(content) => Ok(Some(content)), - Err(_) => Ok(None), - } - })?)?; - - // owlry.fs.read_lines(path) -> table of strings or nil - fs.set("read_lines", lua.create_function(|lua, path: String| { - let path = expand_path(&path); - match std::fs::read_to_string(&path) { - Ok(content) => { - let lines: Vec = content.lines().map(|s| s.to_string()).collect(); - Ok(Some(lua.create_sequence_from(lines)?)) - } - Err(_) => Ok(None), - } - })?)?; - - // owlry.fs.list_dir(path) -> table of filenames or nil - fs.set("list_dir", lua.create_function(|lua, path: String| { - let path = expand_path(&path); - match std::fs::read_dir(&path) { - Ok(entries) => { - let names: Vec = entries - .filter_map(|e| e.ok()) - .filter_map(|e| e.file_name().into_string().ok()) - .collect(); - Ok(Some(lua.create_sequence_from(names)?)) - } - Err(_) => Ok(None), - } - })?)?; - - // owlry.fs.read_json(path) -> table or nil - fs.set("read_json", lua.create_function(|lua, path: String| { - let path = expand_path(&path); - match std::fs::read_to_string(&path) { - Ok(content) => { - match serde_json::from_str::(&content) { - Ok(value) => json_to_lua(lua, &value), - Err(_) => Ok(Value::Nil), - } - } - Err(_) => Ok(Value::Nil), - } - })?)?; - - // owlry.fs.write(path, content) -> bool - fs.set("write", lua.create_function(|_, (path, content): (String, String)| { - let path = expand_path(&path); - // Create parent directories if needed - if let Some(parent) = Path::new(&path).parent() { - let _ = std::fs::create_dir_all(parent); - } - Ok(std::fs::write(&path, content).is_ok()) - })?)?; - - owlry.set("fs", fs)?; - Ok(()) -} - -// ============================================================================ -// JSON API -// ============================================================================ - -/// Register the json API in the owlry table -pub fn register_json_api(lua: &Lua, owlry: &Table) -> LuaResult<()> { - let json = lua.create_table()?; - - // owlry.json.encode(value) -> string - json.set("encode", lua.create_function(|lua, value: Value| { - let json_value = lua_to_json(lua, &value)?; - Ok(serde_json::to_string(&json_value).unwrap_or_else(|_| "null".to_string())) - })?)?; - - // owlry.json.decode(string) -> value or nil - json.set("decode", lua.create_function(|lua, s: String| { - match serde_json::from_str::(&s) { - Ok(value) => json_to_lua(lua, &value), - Err(_) => Ok(Value::Nil), - } - })?)?; - - owlry.set("json", json)?; - Ok(()) -} - -// ============================================================================ -// Helper Functions -// ============================================================================ - -/// Expand ~ in paths -fn expand_path(path: &str) -> String { - if path.starts_with("~/") - && let Some(home) = dirs::home_dir() { - return home.join(&path[2..]).to_string_lossy().to_string(); - } - path.to_string() -} - -/// Convert JSON value to Lua value -fn json_to_lua(lua: &Lua, value: &serde_json::Value) -> LuaResult { - match value { - serde_json::Value::Null => Ok(Value::Nil), - serde_json::Value::Bool(b) => Ok(Value::Boolean(*b)), - serde_json::Value::Number(n) => { - if let Some(i) = n.as_i64() { - Ok(Value::Integer(i)) - } else if let Some(f) = n.as_f64() { - Ok(Value::Number(f)) - } else { - Ok(Value::Nil) - } - } - serde_json::Value::String(s) => Ok(Value::String(lua.create_string(s)?)), - serde_json::Value::Array(arr) => { - let table = lua.create_table()?; - for (i, v) in arr.iter().enumerate() { - table.set(i + 1, json_to_lua(lua, v)?)?; - } - Ok(Value::Table(table)) - } - serde_json::Value::Object(obj) => { - let table = lua.create_table()?; - for (k, v) in obj { - table.set(k.as_str(), json_to_lua(lua, v)?)?; - } - Ok(Value::Table(table)) - } - } -} - -/// Convert Lua value to JSON value -fn lua_to_json(_lua: &Lua, value: &Value) -> LuaResult { - match value { - Value::Nil => Ok(serde_json::Value::Null), - Value::Boolean(b) => Ok(serde_json::Value::Bool(*b)), - Value::Integer(i) => Ok(serde_json::Value::Number((*i).into())), - Value::Number(n) => Ok(serde_json::json!(*n)), - Value::String(s) => Ok(serde_json::Value::String(s.to_str()?.to_string())), - Value::Table(t) => { - // Check if it's an array (sequential integer keys starting from 1) - let mut is_array = true; - let mut max_key = 0i64; - for pair in t.clone().pairs::() { - let (k, _) = pair?; - match k { - Value::Integer(i) if i > 0 => { - max_key = max_key.max(i); - } - _ => { - is_array = false; - break; - } - } - } - - if is_array && max_key > 0 { - let mut arr = Vec::new(); - for i in 1..=max_key { - let v: Value = t.get(i)?; - arr.push(lua_to_json(_lua, &v)?); - } - Ok(serde_json::Value::Array(arr)) - } else { - let mut obj = serde_json::Map::new(); - for pair in t.clone().pairs::() { - let (k, v) = pair?; - obj.insert(k, lua_to_json(_lua, &v)?); - } - Ok(serde_json::Value::Object(obj)) - } - } - _ => Ok(serde_json::Value::Null), - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::runtime::{create_lua_runtime, SandboxConfig}; - - #[test] - fn test_log_api() { - let config = SandboxConfig::default(); - let lua = create_lua_runtime(&config).unwrap(); - let owlry = lua.create_table().unwrap(); - register_log_api(&lua, &owlry).unwrap(); - lua.globals().set("owlry", owlry).unwrap(); - - // Just verify it doesn't panic - lua.load("owlry.log.info('test message')").set_name("test").call::<()>(()).unwrap(); - } - - #[test] - fn test_path_api() { - let config = SandboxConfig::default(); - let lua = create_lua_runtime(&config).unwrap(); - let owlry = lua.create_table().unwrap(); - register_path_api(&lua, &owlry, Path::new("/tmp/test-plugin")).unwrap(); - lua.globals().set("owlry", owlry).unwrap(); - - let home: String = lua.load("return owlry.path.home()").set_name("test").call(()).unwrap(); - assert!(!home.is_empty()); - - let plugin_dir: String = lua.load("return owlry.path.plugin_dir()").set_name("test").call(()).unwrap(); - assert_eq!(plugin_dir, "/tmp/test-plugin"); - } - - #[test] - fn test_fs_api() { - let config = SandboxConfig::default(); - let lua = create_lua_runtime(&config).unwrap(); - let owlry = lua.create_table().unwrap(); - register_fs_api(&lua, &owlry, Path::new("/tmp")).unwrap(); - lua.globals().set("owlry", owlry).unwrap(); - - let exists: bool = lua.load("return owlry.fs.exists('/tmp')").set_name("test").call(()).unwrap(); - assert!(exists); - - let is_dir: bool = lua.load("return owlry.fs.is_dir('/tmp')").set_name("test").call(()).unwrap(); - assert!(is_dir); - } - - #[test] - fn test_json_api() { - let config = SandboxConfig::default(); - let lua = create_lua_runtime(&config).unwrap(); - let owlry = lua.create_table().unwrap(); - register_json_api(&lua, &owlry).unwrap(); - lua.globals().set("owlry", owlry).unwrap(); - - let code = r#" - local t = { name = "test", value = 42 } - local json = owlry.json.encode(t) - local decoded = owlry.json.decode(json) - return decoded.name, decoded.value - "#; - let (name, value): (String, i32) = lua.load(code).set_name("test").call(()).unwrap(); - assert_eq!(name, "test"); - assert_eq!(value, 42); - } -} diff --git a/crates/owlry-lua/src/lib.rs b/crates/owlry-lua/src/lib.rs deleted file mode 100644 index 2ff1204..0000000 --- a/crates/owlry-lua/src/lib.rs +++ /dev/null @@ -1,349 +0,0 @@ -//! Owlry Lua Runtime -//! -//! This crate provides Lua plugin support for owlry. It is loaded dynamically -//! by the core when Lua plugins need to be executed. -//! -//! # Architecture -//! -//! The runtime acts as a "meta-plugin" that: -//! 1. Discovers Lua plugins in `~/.config/owlry/plugins/` -//! 2. Creates sandboxed Lua VMs for each plugin -//! 3. Registers the `owlry` API table -//! 4. Bridges Lua providers to native `PluginItem` format -//! -//! # Plugin Structure -//! -//! Each plugin lives in its own directory: -//! ```text -//! ~/.config/owlry/plugins/ -//! my-plugin/ -//! plugin.toml # Plugin manifest -//! init.lua # Entry point -//! ``` - -mod api; -mod loader; -mod manifest; -mod runtime; - -use abi_stable::std_types::{ROption, RStr, RString, RVec}; -use owlry_plugin_api::{PluginItem, ProviderKind}; -use std::collections::HashMap; -use std::path::PathBuf; - -use loader::LoadedPlugin; - -// Runtime metadata -const RUNTIME_ID: &str = "lua"; -const RUNTIME_NAME: &str = "Lua Runtime"; -const RUNTIME_VERSION: &str = env!("CARGO_PKG_VERSION"); -const RUNTIME_DESCRIPTION: &str = "Lua 5.4 runtime for user plugins"; - -/// API version for compatibility checking -pub const LUA_RUNTIME_API_VERSION: u32 = 1; - -/// Runtime vtable - exported interface for the core to use -#[repr(C)] -pub struct LuaRuntimeVTable { - /// Get runtime info - pub info: extern "C" fn() -> RuntimeInfo, - /// Initialize the runtime with plugins directory - pub init: extern "C" fn(plugins_dir: RStr<'_>) -> RuntimeHandle, - /// Get provider infos from all loaded plugins - pub providers: extern "C" fn(handle: RuntimeHandle) -> RVec, - /// Refresh a provider's items - pub refresh: extern "C" fn(handle: RuntimeHandle, provider_id: RStr<'_>) -> RVec, - /// Query a dynamic provider - pub query: extern "C" fn(handle: RuntimeHandle, provider_id: RStr<'_>, query: RStr<'_>) -> RVec, - /// Cleanup and drop the runtime - pub drop: extern "C" fn(handle: RuntimeHandle), -} - -/// Runtime info returned by the runtime -#[repr(C)] -pub struct RuntimeInfo { - pub id: RString, - pub name: RString, - pub version: RString, - pub description: RString, - pub api_version: u32, -} - -/// Opaque handle to the runtime state -#[repr(C)] -#[derive(Clone, Copy)] -pub struct RuntimeHandle { - pub ptr: *mut (), -} - -unsafe impl Send for RuntimeHandle {} -unsafe impl Sync for RuntimeHandle {} - -impl RuntimeHandle { - /// Create a null handle (reserved for error cases) - #[allow(dead_code)] - fn null() -> Self { - Self { ptr: std::ptr::null_mut() } - } - - fn from_box(state: Box) -> Self { - Self { ptr: Box::into_raw(state) as *mut () } - } - - unsafe fn drop_as(&self) { - if !self.ptr.is_null() { - unsafe { drop(Box::from_raw(self.ptr as *mut T)) }; - } - } -} - -/// Provider info from a Lua plugin -#[repr(C)] -pub struct LuaProviderInfo { - /// Full provider ID: "plugin_id:provider_name" - pub id: RString, - /// Plugin ID this provider belongs to - pub plugin_id: RString, - /// Provider name within the plugin - pub provider_name: RString, - /// Display name - pub display_name: RString, - /// Optional prefix trigger - pub prefix: ROption, - /// Icon name - pub icon: RString, - /// Provider type (static/dynamic) - pub provider_type: ProviderKind, - /// Type ID for filtering - pub type_id: RString, -} - -/// Internal runtime state -struct LuaRuntimeState { - plugins_dir: PathBuf, - plugins: HashMap, - /// Maps "plugin_id:provider_name" to plugin_id for lookup - provider_map: HashMap, -} - -impl LuaRuntimeState { - fn new(plugins_dir: PathBuf) -> Self { - Self { - plugins_dir, - plugins: HashMap::new(), - provider_map: HashMap::new(), - } - } - - fn discover_and_load(&mut self, owlry_version: &str) { - let discovered = match loader::discover_plugins(&self.plugins_dir) { - Ok(d) => d, - Err(e) => { - eprintln!("owlry-lua: Failed to discover plugins: {}", e); - return; - } - }; - - for (id, (manifest, path)) in discovered { - // Check version compatibility - if !manifest.is_compatible_with(owlry_version) { - eprintln!("owlry-lua: Plugin '{}' not compatible with owlry {}", id, owlry_version); - continue; - } - - let mut plugin = LoadedPlugin::new(manifest, path); - if let Err(e) = plugin.initialize() { - eprintln!("owlry-lua: Failed to initialize plugin '{}': {}", id, e); - continue; - } - - // Build provider map - if let Ok(registrations) = plugin.get_provider_registrations() { - for reg in ®istrations { - let full_id = format!("{}:{}", id, reg.name); - self.provider_map.insert(full_id, id.clone()); - } - } - - self.plugins.insert(id, plugin); - } - } - - fn get_providers(&self) -> Vec { - let mut providers = Vec::new(); - - for (plugin_id, plugin) in &self.plugins { - if let Ok(registrations) = plugin.get_provider_registrations() { - for reg in registrations { - let full_id = format!("{}:{}", plugin_id, reg.name); - let provider_type = if reg.is_dynamic { - ProviderKind::Dynamic - } else { - ProviderKind::Static - }; - - providers.push(LuaProviderInfo { - id: RString::from(full_id), - plugin_id: RString::from(plugin_id.as_str()), - provider_name: RString::from(reg.name.as_str()), - display_name: RString::from(reg.display_name.as_str()), - prefix: reg.prefix.map(RString::from).into(), - icon: RString::from(reg.default_icon.as_str()), - provider_type, - type_id: RString::from(reg.type_id.as_str()), - }); - } - } - } - - providers - } - - fn refresh_provider(&self, provider_id: &str) -> Vec { - // Parse "plugin_id:provider_name" - let parts: Vec<&str> = provider_id.splitn(2, ':').collect(); - if parts.len() != 2 { - return Vec::new(); - } - let (plugin_id, provider_name) = (parts[0], parts[1]); - - if let Some(plugin) = self.plugins.get(plugin_id) { - match plugin.call_provider_refresh(provider_name) { - Ok(items) => items, - Err(e) => { - eprintln!("owlry-lua: Refresh failed for {}: {}", provider_id, e); - Vec::new() - } - } - } else { - Vec::new() - } - } - - fn query_provider(&self, provider_id: &str, query: &str) -> Vec { - // Parse "plugin_id:provider_name" - let parts: Vec<&str> = provider_id.splitn(2, ':').collect(); - if parts.len() != 2 { - return Vec::new(); - } - let (plugin_id, provider_name) = (parts[0], parts[1]); - - if let Some(plugin) = self.plugins.get(plugin_id) { - match plugin.call_provider_query(provider_name, query) { - Ok(items) => items, - Err(e) => { - eprintln!("owlry-lua: Query failed for {}: {}", provider_id, e); - Vec::new() - } - } - } else { - Vec::new() - } - } -} - -// ============================================================================ -// Exported Functions -// ============================================================================ - -extern "C" fn runtime_info() -> RuntimeInfo { - RuntimeInfo { - id: RString::from(RUNTIME_ID), - name: RString::from(RUNTIME_NAME), - version: RString::from(RUNTIME_VERSION), - description: RString::from(RUNTIME_DESCRIPTION), - api_version: LUA_RUNTIME_API_VERSION, - } -} - -extern "C" fn runtime_init(plugins_dir: RStr<'_>) -> RuntimeHandle { - let plugins_dir = PathBuf::from(plugins_dir.as_str()); - let mut state = Box::new(LuaRuntimeState::new(plugins_dir)); - - // TODO: Get owlry version from core somehow - // For now, use a reasonable default - state.discover_and_load("0.3.0"); - - RuntimeHandle::from_box(state) -} - -extern "C" fn runtime_providers(handle: RuntimeHandle) -> RVec { - if handle.ptr.is_null() { - return RVec::new(); - } - - let state = unsafe { &*(handle.ptr as *const LuaRuntimeState) }; - state.get_providers().into() -} - -extern "C" fn runtime_refresh(handle: RuntimeHandle, provider_id: RStr<'_>) -> RVec { - if handle.ptr.is_null() { - return RVec::new(); - } - - let state = unsafe { &*(handle.ptr as *const LuaRuntimeState) }; - state.refresh_provider(provider_id.as_str()).into() -} - -extern "C" fn runtime_query(handle: RuntimeHandle, provider_id: RStr<'_>, query: RStr<'_>) -> RVec { - if handle.ptr.is_null() { - return RVec::new(); - } - - let state = unsafe { &*(handle.ptr as *const LuaRuntimeState) }; - state.query_provider(provider_id.as_str(), query.as_str()).into() -} - -extern "C" fn runtime_drop(handle: RuntimeHandle) { - if !handle.ptr.is_null() { - unsafe { - handle.drop_as::(); - } - } -} - -/// Static vtable instance -static LUA_RUNTIME_VTABLE: LuaRuntimeVTable = LuaRuntimeVTable { - info: runtime_info, - init: runtime_init, - providers: runtime_providers, - refresh: runtime_refresh, - query: runtime_query, - drop: runtime_drop, -}; - -/// Entry point - returns the runtime vtable -#[unsafe(no_mangle)] -pub extern "C" fn owlry_lua_runtime_vtable() -> &'static LuaRuntimeVTable { - &LUA_RUNTIME_VTABLE -} - -// ============================================================================ -// Tests -// ============================================================================ - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_runtime_info() { - let info = runtime_info(); - assert_eq!(info.id.as_str(), "lua"); - assert_eq!(info.api_version, LUA_RUNTIME_API_VERSION); - } - - #[test] - fn test_runtime_handle_null() { - let handle = RuntimeHandle::null(); - assert!(handle.ptr.is_null()); - } - - #[test] - fn test_runtime_handle_from_box() { - let state = Box::new(42u32); - let handle = RuntimeHandle::from_box(state); - assert!(!handle.ptr.is_null()); - unsafe { handle.drop_as::() }; - } -} diff --git a/crates/owlry-lua/src/loader.rs b/crates/owlry-lua/src/loader.rs deleted file mode 100644 index c5f5fd4..0000000 --- a/crates/owlry-lua/src/loader.rs +++ /dev/null @@ -1,212 +0,0 @@ -//! Plugin discovery and loading - -use std::collections::HashMap; -use std::path::{Path, PathBuf}; - -use mlua::Lua; -use owlry_plugin_api::PluginItem; - -use crate::api; -use crate::manifest::PluginManifest; -use crate::runtime::{create_lua_runtime, load_file, SandboxConfig}; - -/// Provider registration info from Lua -#[derive(Debug, Clone)] -pub struct ProviderRegistration { - pub name: String, - pub display_name: String, - pub type_id: String, - pub default_icon: String, - pub prefix: Option, - pub is_dynamic: bool, -} - -/// A loaded plugin instance -pub struct LoadedPlugin { - /// Plugin manifest - pub manifest: PluginManifest, - /// Path to plugin directory - pub path: PathBuf, - /// Whether plugin is enabled - pub enabled: bool, - /// Lua runtime (None if not yet initialized) - lua: Option, -} - -impl std::fmt::Debug for LoadedPlugin { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("LoadedPlugin") - .field("manifest", &self.manifest) - .field("path", &self.path) - .field("enabled", &self.enabled) - .field("lua", &self.lua.is_some()) - .finish() - } -} - -impl LoadedPlugin { - /// Create a new loaded plugin (not yet initialized) - pub fn new(manifest: PluginManifest, path: PathBuf) -> Self { - Self { - manifest, - path, - enabled: true, - lua: None, - } - } - - /// Get the plugin ID - pub fn id(&self) -> &str { - &self.manifest.plugin.id - } - - /// Initialize the Lua runtime and load the entry point - pub fn initialize(&mut self) -> Result<(), String> { - if self.lua.is_some() { - return Ok(()); // Already initialized - } - - let sandbox = SandboxConfig::from_permissions(&self.manifest.permissions); - let lua = create_lua_runtime(&sandbox) - .map_err(|e| format!("Failed to create Lua runtime: {}", e))?; - - // Register owlry APIs before loading entry point - api::register_apis(&lua, &self.path, self.id()) - .map_err(|e| format!("Failed to register APIs: {}", e))?; - - // Load the entry point file - let entry_path = self.path.join(&self.manifest.plugin.entry); - if !entry_path.exists() { - return Err(format!("Entry point '{}' not found", self.manifest.plugin.entry)); - } - - load_file(&lua, &entry_path) - .map_err(|e| format!("Failed to load entry point: {}", e))?; - - self.lua = Some(lua); - Ok(()) - } - - /// Get provider registrations from this plugin - pub fn get_provider_registrations(&self) -> Result, String> { - let lua = self.lua.as_ref() - .ok_or_else(|| "Plugin not initialized".to_string())?; - - api::get_provider_registrations(lua) - .map_err(|e| format!("Failed to get registrations: {}", e)) - } - - /// Call a provider's refresh function - pub fn call_provider_refresh(&self, provider_name: &str) -> Result, String> { - let lua = self.lua.as_ref() - .ok_or_else(|| "Plugin not initialized".to_string())?; - - api::call_refresh(lua, provider_name) - .map_err(|e| format!("Refresh failed: {}", e)) - } - - /// Call a provider's query function - pub fn call_provider_query(&self, provider_name: &str, query: &str) -> Result, String> { - let lua = self.lua.as_ref() - .ok_or_else(|| "Plugin not initialized".to_string())?; - - api::call_query(lua, provider_name, query) - .map_err(|e| format!("Query failed: {}", e)) - } -} - -/// Discover plugins in a directory -pub fn discover_plugins(plugins_dir: &Path) -> Result, String> { - let mut plugins = HashMap::new(); - - if !plugins_dir.exists() { - return Ok(plugins); - } - - let entries = std::fs::read_dir(plugins_dir) - .map_err(|e| format!("Failed to read plugins directory: {}", e))?; - - for entry in entries { - let entry = match entry { - Ok(e) => e, - Err(_) => continue, - }; - let path = entry.path(); - - if !path.is_dir() { - continue; - } - - let manifest_path = path.join("plugin.toml"); - if !manifest_path.exists() { - continue; - } - - match PluginManifest::load(&manifest_path) { - Ok(manifest) => { - let id = manifest.plugin.id.clone(); - if plugins.contains_key(&id) { - eprintln!("owlry-lua: Duplicate plugin ID '{}', skipping {}", id, path.display()); - continue; - } - plugins.insert(id, (manifest, path)); - } - Err(e) => { - eprintln!("owlry-lua: Failed to load plugin at {}: {}", path.display(), e); - } - } - } - - Ok(plugins) -} - -#[cfg(test)] -mod tests { - use super::*; - use std::fs; - use tempfile::TempDir; - - fn create_test_plugin(dir: &Path, id: &str) { - let plugin_dir = dir.join(id); - fs::create_dir_all(&plugin_dir).unwrap(); - - let manifest = format!( - r#" -[plugin] -id = "{}" -name = "Test {}" -version = "1.0.0" -"#, - id, id - ); - fs::write(plugin_dir.join("plugin.toml"), manifest).unwrap(); - fs::write(plugin_dir.join("init.lua"), "-- empty plugin").unwrap(); - } - - #[test] - fn test_discover_plugins() { - let temp = TempDir::new().unwrap(); - let plugins_dir = temp.path(); - - create_test_plugin(plugins_dir, "test-plugin"); - create_test_plugin(plugins_dir, "another-plugin"); - - let plugins = discover_plugins(plugins_dir).unwrap(); - assert_eq!(plugins.len(), 2); - assert!(plugins.contains_key("test-plugin")); - assert!(plugins.contains_key("another-plugin")); - } - - #[test] - fn test_discover_plugins_empty_dir() { - let temp = TempDir::new().unwrap(); - let plugins = discover_plugins(temp.path()).unwrap(); - assert!(plugins.is_empty()); - } - - #[test] - fn test_discover_plugins_nonexistent_dir() { - let plugins = discover_plugins(Path::new("/nonexistent/path")).unwrap(); - assert!(plugins.is_empty()); - } -} diff --git a/crates/owlry-lua/src/manifest.rs b/crates/owlry-lua/src/manifest.rs deleted file mode 100644 index fcdd69a..0000000 --- a/crates/owlry-lua/src/manifest.rs +++ /dev/null @@ -1,173 +0,0 @@ -//! Plugin manifest (plugin.toml) parsing - -use serde::{Deserialize, Serialize}; -use std::collections::HashMap; -use std::path::Path; - -/// Plugin manifest loaded from plugin.toml -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct PluginManifest { - pub plugin: PluginInfo, - #[serde(default)] - pub provides: PluginProvides, - #[serde(default)] - pub permissions: PluginPermissions, - #[serde(default)] - pub settings: HashMap, -} - -/// Core plugin information -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct PluginInfo { - /// Unique plugin identifier (lowercase, alphanumeric, hyphens) - pub id: String, - /// Human-readable name - pub name: String, - /// Semantic version - pub version: String, - /// Short description - #[serde(default)] - pub description: String, - /// Plugin author - #[serde(default)] - pub author: String, - /// License identifier - #[serde(default)] - pub license: String, - /// Repository URL - #[serde(default)] - pub repository: Option, - /// Required owlry version (semver constraint) - #[serde(default = "default_owlry_version")] - pub owlry_version: String, - /// Entry point file (relative to plugin directory) - #[serde(default = "default_entry")] - pub entry: String, -} - -fn default_owlry_version() -> String { - ">=0.1.0".to_string() -} - -fn default_entry() -> String { - "init.lua".to_string() -} - -/// What the plugin provides -#[derive(Debug, Clone, Default, Serialize, Deserialize)] -pub struct PluginProvides { - /// Provider names this plugin registers - #[serde(default)] - pub providers: Vec, - /// Whether this plugin registers actions - #[serde(default)] - pub actions: bool, - /// Theme names this plugin contributes - #[serde(default)] - pub themes: Vec, - /// Whether this plugin registers hooks - #[serde(default)] - pub hooks: bool, -} - -/// Plugin permissions/capabilities -#[derive(Debug, Clone, Default, Serialize, Deserialize)] -pub struct PluginPermissions { - /// Allow network/HTTP requests - #[serde(default)] - pub network: bool, - /// Filesystem paths the plugin can access (beyond its own directory) - #[serde(default)] - pub filesystem: Vec, - /// Commands the plugin is allowed to run - #[serde(default)] - pub run_commands: Vec, - /// Environment variables the plugin reads - #[serde(default)] - pub environment: Vec, -} - -impl PluginManifest { - /// Load a plugin manifest from a plugin.toml file - pub fn load(path: &Path) -> Result { - let content = std::fs::read_to_string(path) - .map_err(|e| format!("Failed to read manifest: {}", e))?; - let manifest: PluginManifest = toml::from_str(&content) - .map_err(|e| format!("Failed to parse manifest: {}", e))?; - manifest.validate()?; - Ok(manifest) - } - - /// Validate the manifest - fn validate(&self) -> Result<(), String> { - // Validate plugin ID format - if self.plugin.id.is_empty() { - return Err("Plugin ID cannot be empty".to_string()); - } - - if !self.plugin.id.chars().all(|c| c.is_ascii_lowercase() || c.is_ascii_digit() || c == '-') { - return Err("Plugin ID must be lowercase alphanumeric with hyphens".to_string()); - } - - // Validate version format - if semver::Version::parse(&self.plugin.version).is_err() { - return Err(format!("Invalid version format: {}", self.plugin.version)); - } - - // Validate owlry_version constraint - if semver::VersionReq::parse(&self.plugin.owlry_version).is_err() { - return Err(format!("Invalid owlry_version constraint: {}", self.plugin.owlry_version)); - } - - Ok(()) - } - - /// Check if this plugin is compatible with the given owlry version - pub fn is_compatible_with(&self, owlry_version: &str) -> bool { - let req = match semver::VersionReq::parse(&self.plugin.owlry_version) { - Ok(r) => r, - Err(_) => return false, - }; - let version = match semver::Version::parse(owlry_version) { - Ok(v) => v, - Err(_) => return false, - }; - req.matches(&version) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_parse_minimal_manifest() { - let toml_str = r#" -[plugin] -id = "test-plugin" -name = "Test Plugin" -version = "1.0.0" -"#; - let manifest: PluginManifest = toml::from_str(toml_str).unwrap(); - assert_eq!(manifest.plugin.id, "test-plugin"); - assert_eq!(manifest.plugin.name, "Test Plugin"); - assert_eq!(manifest.plugin.version, "1.0.0"); - assert_eq!(manifest.plugin.entry, "init.lua"); - } - - #[test] - fn test_version_compatibility() { - let toml_str = r#" -[plugin] -id = "test" -name = "Test" -version = "1.0.0" -owlry_version = ">=0.3.0, <1.0.0" -"#; - let manifest: PluginManifest = toml::from_str(toml_str).unwrap(); - assert!(manifest.is_compatible_with("0.3.5")); - assert!(manifest.is_compatible_with("0.4.0")); - assert!(!manifest.is_compatible_with("0.2.0")); - assert!(!manifest.is_compatible_with("1.0.0")); - } -} diff --git a/crates/owlry-lua/src/runtime.rs b/crates/owlry-lua/src/runtime.rs deleted file mode 100644 index 4a2664c..0000000 --- a/crates/owlry-lua/src/runtime.rs +++ /dev/null @@ -1,153 +0,0 @@ -//! Lua runtime setup and sandboxing - -use mlua::{Lua, Result as LuaResult, StdLib}; - -use crate::manifest::PluginPermissions; - -/// Configuration for the Lua sandbox -/// -/// Note: Some fields are reserved for future sandbox enforcement. -#[derive(Debug, Clone)] -#[allow(dead_code)] -pub struct SandboxConfig { - /// Allow shell command running (reserved for future enforcement) - pub allow_commands: bool, - /// Allow HTTP requests (reserved for future enforcement) - pub allow_network: bool, - /// Allow filesystem access outside plugin directory (reserved for future enforcement) - pub allow_external_fs: bool, - /// Maximum run time per call (ms) (reserved for future enforcement) - pub max_run_time_ms: u64, - /// Memory limit (bytes, 0 = unlimited) (reserved for future enforcement) - pub max_memory: usize, -} - -impl Default for SandboxConfig { - fn default() -> Self { - Self { - allow_commands: false, - allow_network: false, - allow_external_fs: false, - max_run_time_ms: 5000, // 5 seconds - max_memory: 64 * 1024 * 1024, // 64 MB - } - } -} - -impl SandboxConfig { - /// Create a sandbox config from plugin permissions - pub fn from_permissions(permissions: &PluginPermissions) -> Self { - Self { - allow_commands: !permissions.run_commands.is_empty(), - allow_network: permissions.network, - allow_external_fs: !permissions.filesystem.is_empty(), - ..Default::default() - } - } -} - -/// Create a new sandboxed Lua runtime -pub fn create_lua_runtime(_sandbox: &SandboxConfig) -> LuaResult { - // Create Lua with safe standard libraries only - // We exclude: debug, io, os (dangerous parts), package (loadlib), ffi - let libs = StdLib::COROUTINE - | StdLib::TABLE - | StdLib::STRING - | StdLib::UTF8 - | StdLib::MATH; - - let lua = Lua::new_with(libs, mlua::LuaOptions::default())?; - - // Set up safe environment - setup_safe_globals(&lua)?; - - Ok(lua) -} - -/// Set up safe global environment by removing/replacing dangerous functions -fn setup_safe_globals(lua: &Lua) -> LuaResult<()> { - let globals = lua.globals(); - - // Remove dangerous globals - globals.set("dofile", mlua::Value::Nil)?; - globals.set("loadfile", mlua::Value::Nil)?; - - // Create a restricted os table with only safe functions - let os_table = lua.create_table()?; - os_table.set("clock", lua.create_function(|_, ()| { - Ok(std::time::Instant::now().elapsed().as_secs_f64()) - })?)?; - os_table.set("date", lua.create_function(os_date)?)?; - os_table.set("difftime", lua.create_function(|_, (t2, t1): (f64, f64)| Ok(t2 - t1))?)?; - os_table.set("time", lua.create_function(os_time)?)?; - globals.set("os", os_table)?; - - // Remove print (plugins should use owlry.log instead) - globals.set("print", mlua::Value::Nil)?; - - Ok(()) -} - -/// Safe os.date implementation -fn os_date(_lua: &Lua, format: Option) -> LuaResult { - use chrono::Local; - let now = Local::now(); - let fmt = format.unwrap_or_else(|| "%c".to_string()); - Ok(now.format(&fmt).to_string()) -} - -/// Safe os.time implementation -fn os_time(_lua: &Lua, _args: ()) -> LuaResult { - use std::time::{SystemTime, UNIX_EPOCH}; - let duration = SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap_or_default(); - Ok(duration.as_secs() as i64) -} - -/// Load and run a Lua file in the given runtime -pub fn load_file(lua: &Lua, path: &std::path::Path) -> LuaResult<()> { - let content = std::fs::read_to_string(path) - .map_err(mlua::Error::external)?; - lua.load(&content) - .set_name(path.file_name().and_then(|n| n.to_str()).unwrap_or("chunk")) - .into_function()? - .call(()) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_create_sandboxed_runtime() { - let config = SandboxConfig::default(); - let lua = create_lua_runtime(&config).unwrap(); - - // Verify dangerous functions are removed - let result: LuaResult = lua.globals().get("dofile"); - assert!(matches!(result, Ok(mlua::Value::Nil))); - - // Verify safe functions work - let result: String = lua.load("return os.date('%Y')").call(()).unwrap(); - assert!(!result.is_empty()); - } - - #[test] - fn test_basic_lua_operations() { - let config = SandboxConfig::default(); - let lua = create_lua_runtime(&config).unwrap(); - - // Test basic math - let result: i32 = lua.load("return 2 + 2").call(()).unwrap(); - assert_eq!(result, 4); - - // Test table operations - let result: i32 = lua.load("local t = {1,2,3}; return #t").call(()).unwrap(); - assert_eq!(result, 3); - - // Test string operations - let result: String = lua.load("return string.upper('hello')").call(()).unwrap(); - assert_eq!(result, "HELLO"); - } -} diff --git a/crates/owlry-rune/Cargo.toml b/crates/owlry-rune/Cargo.toml deleted file mode 100644 index c86e5c0..0000000 --- a/crates/owlry-rune/Cargo.toml +++ /dev/null @@ -1,44 +0,0 @@ -[package] -name = "owlry-rune" -version = "0.4.10" -edition = "2024" -rust-version = "1.90" -description = "Rune scripting runtime for owlry plugins" -license = "GPL-3.0-or-later" - -[lib] -crate-type = ["cdylib"] - -[dependencies] -# Shared plugin API -owlry-plugin-api = { path = "/home/cnachtigall/ssd/git/archive/owlibou/owlry/crates/owlry-plugin-api" } - -# Rune scripting language -rune = "0.14" -rune-modules = { version = "0.14", features = ["full"] } - -# Logging -log = "0.4" -env_logger = "0.11" - -# HTTP client for network API -reqwest = { version = "0.13", default-features = false, features = ["rustls", "json", "blocking"] } - -# Serialization -serde = { version = "1", features = ["derive"] } -serde_json = "1" - -# Configuration parsing -toml = "0.8" - -# Semantic versioning -semver = "1" - -# Date/time -chrono = "0.4" - -# Directory paths -dirs = "5" - -[dev-dependencies] -tempfile = "3" diff --git a/crates/owlry-rune/src/api.rs b/crates/owlry-rune/src/api.rs deleted file mode 100644 index 5f28498..0000000 --- a/crates/owlry-rune/src/api.rs +++ /dev/null @@ -1,130 +0,0 @@ -//! Owlry API bindings for Rune plugins -//! -//! This module provides the `owlry` module that Rune plugins can use. - -use rune::{ContextError, Module}; -use std::sync::Mutex; - -use owlry_plugin_api::{PluginItem, RString}; - -/// Provider registration info -#[derive(Debug, Clone)] -pub struct ProviderRegistration { - pub name: String, - pub display_name: String, - pub type_id: String, - pub default_icon: String, - pub is_static: bool, - pub prefix: Option, -} - -/// An item returned by a provider -/// -/// Used for converting Rune plugin items to FFI format. -#[derive(Debug, Clone)] -#[allow(dead_code)] -pub struct Item { - pub id: String, - pub name: String, - pub description: Option, - pub icon: Option, - pub command: String, - pub terminal: bool, - pub keywords: Vec, -} - -impl Item { - /// Convert to PluginItem for FFI - #[allow(dead_code)] - pub fn to_plugin_item(&self) -> PluginItem { - let mut item = PluginItem::new( - RString::from(self.id.as_str()), - RString::from(self.name.as_str()), - RString::from(self.command.as_str()), - ); - - if let Some(ref desc) = self.description { - item = item.with_description(desc.clone()); - } - if let Some(ref icon) = self.icon { - item = item.with_icon(icon.clone()); - } - - item.with_terminal(self.terminal) - .with_keywords(self.keywords.clone()) - } -} - -/// Global state for provider registrations (thread-safe) -pub static REGISTRATIONS: Mutex> = Mutex::new(Vec::new()); - -/// Create the owlry module for Rune -pub fn module() -> Result { - let mut module = Module::with_crate("owlry")?; - - // Register logging functions using builder pattern - module.function("log_info", log_info).build()?; - module.function("log_debug", log_debug).build()?; - module.function("log_warn", log_warn).build()?; - module.function("log_error", log_error).build()?; - - Ok(module) -} - -// ============================================================================ -// Logging Functions -// ============================================================================ - -fn log_info(message: &str) { - log::info!("[Rune] {}", message); -} - -fn log_debug(message: &str) { - log::debug!("[Rune] {}", message); -} - -fn log_warn(message: &str) { - log::warn!("[Rune] {}", message); -} - -fn log_error(message: &str) { - log::error!("[Rune] {}", message); -} - -/// Get all provider registrations -pub fn get_registrations() -> Vec { - REGISTRATIONS.lock().unwrap().clone() -} - -/// Clear all registrations (for testing or reloading) -pub fn clear_registrations() { - REGISTRATIONS.lock().unwrap().clear(); -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_item_creation() { - let item = Item { - id: "test-1".to_string(), - name: "Test Item".to_string(), - description: Some("A test".to_string()), - icon: Some("test-icon".to_string()), - command: "echo test".to_string(), - terminal: false, - keywords: vec!["test".to_string()], - }; - - let plugin_item = item.to_plugin_item(); - assert_eq!(plugin_item.id.as_str(), "test-1"); - assert_eq!(plugin_item.name.as_str(), "Test Item"); - } - - #[test] - fn test_module_creation() { - let module = module(); - assert!(module.is_ok()); - } -} diff --git a/crates/owlry-rune/src/lib.rs b/crates/owlry-rune/src/lib.rs deleted file mode 100644 index 4476840..0000000 --- a/crates/owlry-rune/src/lib.rs +++ /dev/null @@ -1,251 +0,0 @@ -//! Owlry Rune Runtime -//! -//! This crate provides a Rune scripting runtime for owlry user plugins. -//! It is loaded dynamically by the core when installed. -//! -//! # Architecture -//! -//! The runtime exports a C-compatible vtable that the core uses to: -//! 1. Initialize the runtime with a plugins directory -//! 2. Get a list of providers from loaded plugins -//! 3. Refresh/query providers -//! 4. Clean up resources -//! -//! # Plugin Structure -//! -//! Rune plugins live in `~/.config/owlry/plugins//`: -//! ```text -//! my-plugin/ -//! plugin.toml # Manifest -//! init.rn # Entry point (Rune script) -//! ``` - -mod api; -mod loader; -mod manifest; -mod runtime; - -use std::collections::HashMap; -use std::path::PathBuf; -use std::sync::Mutex; - -use owlry_plugin_api::{PluginItem, ROption, RStr, RString, RVec}; - -pub use loader::LoadedPlugin; -pub use manifest::PluginManifest; - -// ============================================================================ -// Runtime VTable (C-compatible interface) -// ============================================================================ - -/// Information about this runtime -#[repr(C)] -pub struct RuntimeInfo { - pub name: RString, - pub version: RString, -} - -/// Information about a provider from a plugin -#[repr(C)] -#[derive(Clone)] -pub struct RuneProviderInfo { - pub name: RString, - pub display_name: RString, - pub type_id: RString, - pub default_icon: RString, - pub is_static: bool, - pub prefix: ROption, -} - -/// Opaque handle to runtime state -#[repr(transparent)] -#[derive(Clone, Copy)] -pub struct RuntimeHandle(pub *mut ()); - -/// Runtime state managed by the handle -struct RuntimeState { - plugins: HashMap, - providers: Vec, -} - -/// VTable for the Rune runtime -#[repr(C)] -pub struct RuneRuntimeVTable { - pub info: extern "C" fn() -> RuntimeInfo, - pub init: extern "C" fn(plugins_dir: RStr<'_>) -> RuntimeHandle, - pub providers: extern "C" fn(handle: RuntimeHandle) -> RVec, - pub refresh: extern "C" fn(handle: RuntimeHandle, provider_id: RStr<'_>) -> RVec, - pub query: extern "C" fn(handle: RuntimeHandle, provider_id: RStr<'_>, query: RStr<'_>) -> RVec, - pub drop: extern "C" fn(handle: RuntimeHandle), -} - -// ============================================================================ -// VTable Implementation -// ============================================================================ - -extern "C" fn runtime_info() -> RuntimeInfo { - RuntimeInfo { - name: RString::from("rune"), - version: RString::from(env!("CARGO_PKG_VERSION")), - } -} - -extern "C" fn runtime_init(plugins_dir: RStr<'_>) -> RuntimeHandle { - let _ = env_logger::try_init(); - - let plugins_dir = PathBuf::from(plugins_dir.as_str()); - log::info!("Initializing Rune runtime with plugins from: {}", plugins_dir.display()); - - let mut state = RuntimeState { - plugins: HashMap::new(), - providers: Vec::new(), - }; - - // Discover and load Rune plugins - match loader::discover_rune_plugins(&plugins_dir) { - Ok(plugins) => { - for (id, plugin) in plugins { - // Collect provider info before storing plugin - for reg in plugin.provider_registrations() { - state.providers.push(RuneProviderInfo { - name: RString::from(reg.name.as_str()), - display_name: RString::from(reg.display_name.as_str()), - type_id: RString::from(reg.type_id.as_str()), - default_icon: RString::from(reg.default_icon.as_str()), - is_static: reg.is_static, - prefix: reg.prefix.as_ref() - .map(|p| RString::from(p.as_str())) - .into(), - }); - } - state.plugins.insert(id, plugin); - } - log::info!("Loaded {} Rune plugin(s) with {} provider(s)", - state.plugins.len(), state.providers.len()); - } - Err(e) => { - log::error!("Failed to discover Rune plugins: {}", e); - } - } - - // Box and leak the state, returning an opaque handle - let boxed = Box::new(Mutex::new(state)); - RuntimeHandle(Box::into_raw(boxed) as *mut ()) -} - -extern "C" fn runtime_providers(handle: RuntimeHandle) -> RVec { - let state = unsafe { &*(handle.0 as *const Mutex) }; - let guard = state.lock().unwrap(); - guard.providers.clone().into_iter().collect() -} - -extern "C" fn runtime_refresh(handle: RuntimeHandle, provider_id: RStr<'_>) -> RVec { - let state = unsafe { &*(handle.0 as *const Mutex) }; - let mut guard = state.lock().unwrap(); - - let provider_name = provider_id.as_str(); - - // Find the plugin that provides this provider - for plugin in guard.plugins.values_mut() { - if plugin.provides_provider(provider_name) { - match plugin.refresh_provider(provider_name) { - Ok(items) => return items.into_iter().collect(), - Err(e) => { - log::error!("Failed to refresh provider '{}': {}", provider_name, e); - return RVec::new(); - } - } - } - } - - log::warn!("Provider '{}' not found", provider_name); - RVec::new() -} - -extern "C" fn runtime_query( - handle: RuntimeHandle, - provider_id: RStr<'_>, - query: RStr<'_>, -) -> RVec { - let state = unsafe { &*(handle.0 as *const Mutex) }; - let mut guard = state.lock().unwrap(); - - let provider_name = provider_id.as_str(); - let query_str = query.as_str(); - - // Find the plugin that provides this provider - for plugin in guard.plugins.values_mut() { - if plugin.provides_provider(provider_name) { - match plugin.query_provider(provider_name, query_str) { - Ok(items) => return items.into_iter().collect(), - Err(e) => { - log::error!("Failed to query provider '{}': {}", provider_name, e); - return RVec::new(); - } - } - } - } - - log::warn!("Provider '{}' not found", provider_name); - RVec::new() -} - -extern "C" fn runtime_drop(handle: RuntimeHandle) { - if !handle.0.is_null() { - // SAFETY: We created this box in runtime_init - unsafe { - let _ = Box::from_raw(handle.0 as *mut Mutex); - } - log::info!("Rune runtime cleaned up"); - } -} - -/// Static vtable instance -static RUNE_RUNTIME_VTABLE: RuneRuntimeVTable = RuneRuntimeVTable { - info: runtime_info, - init: runtime_init, - providers: runtime_providers, - refresh: runtime_refresh, - query: runtime_query, - drop: runtime_drop, -}; - -/// Entry point - returns the runtime vtable -#[unsafe(no_mangle)] -pub extern "C" fn owlry_rune_runtime_vtable() -> &'static RuneRuntimeVTable { - &RUNE_RUNTIME_VTABLE -} - -// ============================================================================ -// Tests -// ============================================================================ - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_runtime_info() { - let info = runtime_info(); - assert_eq!(info.name.as_str(), "rune"); - assert!(!info.version.as_str().is_empty()); - } - - #[test] - fn test_runtime_lifecycle() { - // Create a temp directory for plugins - let temp = tempfile::TempDir::new().unwrap(); - let plugins_dir = temp.path().to_string_lossy(); - - // Initialize runtime - let handle = runtime_init(RStr::from_str(&plugins_dir)); - assert!(!handle.0.is_null()); - - // Get providers (should be empty with no plugins) - let providers = runtime_providers(handle); - assert!(providers.is_empty()); - - // Clean up - runtime_drop(handle); - } -} diff --git a/crates/owlry-rune/src/loader.rs b/crates/owlry-rune/src/loader.rs deleted file mode 100644 index 9c0a869..0000000 --- a/crates/owlry-rune/src/loader.rs +++ /dev/null @@ -1,175 +0,0 @@ -//! Rune plugin discovery and loading - -use std::collections::HashMap; -use std::path::{Path, PathBuf}; -use std::sync::Arc; - -use rune::{Context, Unit}; - -use crate::api::{self, ProviderRegistration}; -use crate::manifest::PluginManifest; -use crate::runtime::{compile_source, create_context, create_vm, SandboxConfig}; - -use owlry_plugin_api::PluginItem; - -/// A loaded Rune plugin -pub struct LoadedPlugin { - pub manifest: PluginManifest, - pub path: PathBuf, - /// Context for creating new VMs (reserved for refresh/query implementation) - #[allow(dead_code)] - context: Context, - /// Compiled unit (reserved for refresh/query implementation) - #[allow(dead_code)] - unit: Arc, - registrations: Vec, -} - -impl LoadedPlugin { - /// Create and initialize a new plugin - pub fn new(manifest: PluginManifest, path: PathBuf) -> Result { - let sandbox = SandboxConfig::from_permissions(&manifest.permissions); - let context = create_context(&sandbox) - .map_err(|e| format!("Failed to create context: {}", e))?; - - let entry_path = path.join(&manifest.plugin.entry); - if !entry_path.exists() { - return Err(format!("Entry point not found: {}", entry_path.display())); - } - - // Clear previous registrations before loading - api::clear_registrations(); - - // Compile the source - let unit = compile_source(&context, &entry_path) - .map_err(|e| format!("Failed to compile: {}", e))?; - - // Run the entry point to register providers - let mut vm = create_vm(&context, unit.clone()) - .map_err(|e| format!("Failed to create VM: {}", e))?; - - // Execute the main function if it exists - match vm.call(rune::Hash::type_hash(["main"]), ()) { - Ok(result) => { - // Try to complete the execution - let _: () = rune::from_value(result) - .unwrap_or(()); - } - Err(_) => { - // No main function is okay - } - } - - // Collect registrations - let registrations = api::get_registrations(); - - log::info!( - "Loaded Rune plugin '{}' with {} provider(s)", - manifest.plugin.id, - registrations.len() - ); - - Ok(Self { - manifest, - path, - context, - unit, - registrations, - }) - } - - /// Get plugin ID - pub fn id(&self) -> &str { - &self.manifest.plugin.id - } - - /// Get provider registrations - pub fn provider_registrations(&self) -> &[ProviderRegistration] { - &self.registrations - } - - /// Check if this plugin provides a specific provider - pub fn provides_provider(&self, name: &str) -> bool { - self.registrations.iter().any(|r| r.name == name) - } - - /// Refresh a static provider (stub for now) - pub fn refresh_provider(&mut self, _name: &str) -> Result, String> { - // TODO: Implement provider refresh by calling Rune function - Ok(Vec::new()) - } - - /// Query a dynamic provider (stub for now) - pub fn query_provider(&mut self, _name: &str, _query: &str) -> Result, String> { - // TODO: Implement provider query by calling Rune function - Ok(Vec::new()) - } -} - -/// Discover Rune plugins in a directory -pub fn discover_rune_plugins(plugins_dir: &Path) -> Result, String> { - let mut plugins = HashMap::new(); - - if !plugins_dir.exists() { - log::debug!("Plugins directory does not exist: {}", plugins_dir.display()); - return Ok(plugins); - } - - let entries = std::fs::read_dir(plugins_dir) - .map_err(|e| format!("Failed to read plugins directory: {}", e))?; - - for entry in entries { - let entry = entry.map_err(|e| format!("Failed to read entry: {}", e))?; - let path = entry.path(); - - if !path.is_dir() { - continue; - } - - let manifest_path = path.join("plugin.toml"); - if !manifest_path.exists() { - continue; - } - - // Load manifest - let manifest = match PluginManifest::load(&manifest_path) { - Ok(m) => m, - Err(e) => { - log::warn!("Failed to load manifest at {}: {}", manifest_path.display(), e); - continue; - } - }; - - // Check if this is a Rune plugin (entry ends with .rn) - if !manifest.plugin.entry.ends_with(".rn") { - log::debug!("Skipping non-Rune plugin: {}", manifest.plugin.id); - continue; - } - - // Load the plugin - match LoadedPlugin::new(manifest.clone(), path.clone()) { - Ok(plugin) => { - let id = manifest.plugin.id.clone(); - plugins.insert(id, plugin); - } - Err(e) => { - log::warn!("Failed to load plugin '{}': {}", manifest.plugin.id, e); - } - } - } - - Ok(plugins) -} - -#[cfg(test)] -mod tests { - use super::*; - use tempfile::TempDir; - - #[test] - fn test_discover_empty_dir() { - let temp = TempDir::new().unwrap(); - let plugins = discover_rune_plugins(temp.path()).unwrap(); - assert!(plugins.is_empty()); - } -} diff --git a/crates/owlry-rune/src/manifest.rs b/crates/owlry-rune/src/manifest.rs deleted file mode 100644 index 7c7946b..0000000 --- a/crates/owlry-rune/src/manifest.rs +++ /dev/null @@ -1,155 +0,0 @@ -//! Plugin manifest parsing for Rune plugins - -use serde::Deserialize; -use std::path::Path; - -/// Plugin manifest from plugin.toml -#[derive(Debug, Clone, Deserialize)] -pub struct PluginManifest { - pub plugin: PluginInfo, - #[serde(default)] - pub provides: PluginProvides, - #[serde(default)] - pub permissions: PluginPermissions, -} - -/// Core plugin information -#[derive(Debug, Clone, Deserialize)] -pub struct PluginInfo { - pub id: String, - pub name: String, - pub version: String, - #[serde(default)] - pub description: String, - #[serde(default)] - pub author: String, - #[serde(default = "default_owlry_version")] - pub owlry_version: String, - #[serde(default = "default_entry")] - pub entry: String, -} - -fn default_owlry_version() -> String { - ">=0.1.0".to_string() -} - -fn default_entry() -> String { - "init.rn".to_string() -} - -/// What the plugin provides -#[derive(Debug, Clone, Default, Deserialize)] -pub struct PluginProvides { - #[serde(default)] - pub providers: Vec, - #[serde(default)] - pub actions: bool, - #[serde(default)] - pub themes: Vec, - #[serde(default)] - pub hooks: bool, -} - -/// Plugin permissions -#[derive(Debug, Clone, Default, Deserialize)] -pub struct PluginPermissions { - #[serde(default)] - pub network: bool, - #[serde(default)] - pub filesystem: Vec, - #[serde(default)] - pub run_commands: Vec, -} - -impl PluginManifest { - /// Load manifest from a plugin.toml file - pub fn load(path: &Path) -> Result { - let content = std::fs::read_to_string(path) - .map_err(|e| format!("Failed to read manifest: {}", e))?; - let manifest: PluginManifest = toml::from_str(&content) - .map_err(|e| format!("Failed to parse manifest: {}", e))?; - manifest.validate()?; - Ok(manifest) - } - - /// Validate the manifest - fn validate(&self) -> Result<(), String> { - if self.plugin.id.is_empty() { - return Err("Plugin ID cannot be empty".to_string()); - } - - if !self.plugin.id.chars().all(|c| c.is_ascii_lowercase() || c.is_ascii_digit() || c == '-') { - return Err("Plugin ID must be lowercase alphanumeric with hyphens".to_string()); - } - - // Validate version format - if semver::Version::parse(&self.plugin.version).is_err() { - return Err(format!("Invalid version format: {}", self.plugin.version)); - } - - // Rune plugins must have .rn entry point - if !self.plugin.entry.ends_with(".rn") { - return Err("Entry point must be a .rn file for Rune plugins".to_string()); - } - - Ok(()) - } - - /// Check compatibility with owlry version - pub fn is_compatible_with(&self, owlry_version: &str) -> bool { - let req = match semver::VersionReq::parse(&self.plugin.owlry_version) { - Ok(r) => r, - Err(_) => return false, - }; - let version = match semver::Version::parse(owlry_version) { - Ok(v) => v, - Err(_) => return false, - }; - req.matches(&version) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_parse_minimal_manifest() { - let toml_str = r#" -[plugin] -id = "test-plugin" -name = "Test Plugin" -version = "1.0.0" -"#; - let manifest: PluginManifest = toml::from_str(toml_str).unwrap(); - assert_eq!(manifest.plugin.id, "test-plugin"); - assert_eq!(manifest.plugin.entry, "init.rn"); - } - - #[test] - fn test_validate_entry_point() { - let toml_str = r#" -[plugin] -id = "test" -name = "Test" -version = "1.0.0" -entry = "main.lua" -"#; - let manifest: PluginManifest = toml::from_str(toml_str).unwrap(); - assert!(manifest.validate().is_err()); // .lua not allowed for Rune - } - - #[test] - fn test_version_compatibility() { - let toml_str = r#" -[plugin] -id = "test" -name = "Test" -version = "1.0.0" -owlry_version = ">=0.3.0" -"#; - let manifest: PluginManifest = toml::from_str(toml_str).unwrap(); - assert!(manifest.is_compatible_with("0.3.5")); - assert!(!manifest.is_compatible_with("0.2.0")); - } -} diff --git a/crates/owlry-rune/src/runtime.rs b/crates/owlry-rune/src/runtime.rs deleted file mode 100644 index 7b60310..0000000 --- a/crates/owlry-rune/src/runtime.rs +++ /dev/null @@ -1,160 +0,0 @@ -//! Rune VM runtime creation and sandboxing - -use rune::{Context, Diagnostics, Source, Sources, Unit, Vm}; -use std::path::Path; -use std::sync::Arc; - -use crate::manifest::PluginPermissions; - -/// Configuration for the Rune sandbox -/// -/// Some fields are reserved for future sandbox enforcement. -#[derive(Debug, Clone)] -#[allow(dead_code)] -#[derive(Default)] -pub struct SandboxConfig { - /// Allow network/HTTP operations - pub network: bool, - /// Allow filesystem operations - pub filesystem: bool, - /// Allowed filesystem paths (reserved for future sandbox enforcement) - pub allowed_paths: Vec, - /// Allow running external commands (reserved for future sandbox enforcement) - pub run_commands: bool, - /// Allowed commands (reserved for future sandbox enforcement) - pub allowed_commands: Vec, -} - - -impl SandboxConfig { - /// Create sandbox config from plugin permissions - pub fn from_permissions(permissions: &PluginPermissions) -> Self { - Self { - network: permissions.network, - filesystem: !permissions.filesystem.is_empty(), - allowed_paths: permissions.filesystem.clone(), - run_commands: !permissions.run_commands.is_empty(), - allowed_commands: permissions.run_commands.clone(), - } - } -} - -/// Create a Rune context with owlry API modules -pub fn create_context(sandbox: &SandboxConfig) -> Result { - let mut context = Context::with_default_modules()?; - - // Add standard modules based on permissions - if sandbox.network { - log::debug!("Network access enabled for Rune plugin"); - } - - if sandbox.filesystem { - log::debug!("Filesystem access enabled for Rune plugin"); - } - - // Add owlry API module - context.install(crate::api::module()?)?; - - Ok(context) -} - -/// Compile Rune source code into a Unit -pub fn compile_source( - context: &Context, - source_path: &Path, -) -> Result, CompileError> { - let source_content = std::fs::read_to_string(source_path) - .map_err(|e| CompileError::Io(e.to_string()))?; - - let source_name = source_path - .file_name() - .and_then(|n| n.to_str()) - .unwrap_or("init.rn"); - - let mut sources = Sources::new(); - sources - .insert(Source::new(source_name, &source_content).map_err(|e| CompileError::Compile(e.to_string()))?) - .map_err(|e| CompileError::Compile(format!("Failed to insert source: {}", e)))?; - - let mut diagnostics = Diagnostics::new(); - - let result = rune::prepare(&mut sources) - .with_context(context) - .with_diagnostics(&mut diagnostics) - .build(); - - match result { - Ok(unit) => Ok(Arc::new(unit)), - Err(e) => { - // Collect error messages - let mut error_msg = format!("Compilation failed: {}", e); - for diagnostic in diagnostics.diagnostics() { - error_msg.push_str(&format!("\n {:?}", diagnostic)); - } - Err(CompileError::Compile(error_msg)) - } - } -} - -/// Create a new Rune VM from compiled unit -pub fn create_vm( - context: &Context, - unit: Arc, -) -> Result { - let runtime = Arc::new( - context.runtime() - .map_err(|e| CompileError::Compile(format!("Failed to get runtime: {}", e)))? - ); - Ok(Vm::new(runtime, unit)) -} - -/// Error type for compilation -#[derive(Debug)] -pub enum CompileError { - Io(String), - Compile(String), -} - -impl std::fmt::Display for CompileError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - CompileError::Io(e) => write!(f, "IO error: {}", e), - CompileError::Compile(e) => write!(f, "Compile error: {}", e), - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_sandbox_config_default() { - let config = SandboxConfig::default(); - assert!(!config.network); - assert!(!config.filesystem); - assert!(!config.run_commands); - } - - #[test] - fn test_sandbox_from_permissions() { - let permissions = PluginPermissions { - network: true, - filesystem: vec!["~/.config".to_string()], - run_commands: vec!["notify-send".to_string()], - }; - let config = SandboxConfig::from_permissions(&permissions); - assert!(config.network); - assert!(config.filesystem); - assert!(config.run_commands); - assert_eq!(config.allowed_paths, vec!["~/.config"]); - assert_eq!(config.allowed_commands, vec!["notify-send"]); - } - - #[test] - fn test_create_context() { - let config = SandboxConfig::default(); - let context = create_context(&config); - assert!(context.is_ok()); - } -} diff --git a/justfile b/justfile index 4a6371b..cb74f42 100644 --- a/justfile +++ b/justfile @@ -24,7 +24,7 @@ plugins: cargo build --workspace --release show-versions: - @for dir in crates/owlry-plugin-* crates/owlry-lua crates/owlry-rune; do \ + @for dir in crates/owlry-plugin-*; do \ name=$$(basename $$dir); \ version=$$(grep '^version' $$dir/Cargo.toml | head -1 | cut -d'"' -f2); \ printf "%-35s %s\n" "$$name" "$$version"; \ @@ -36,7 +36,7 @@ bump-crate crate new_version: @echo "Bumped {{crate}} to {{new_version}}" bump-all new_version: - @for dir in crates/owlry-plugin-* crates/owlry-lua crates/owlry-rune; do \ + @for dir in crates/owlry-plugin-*; do \ sed -i 's/^version = ".*"/version = "{{new_version}}"/' $$dir/Cargo.toml; \ done @echo "Bumped all crates to {{new_version}}" @@ -46,7 +46,4 @@ install-local: @for f in target/release/libowlry_plugin_*.so; do \ sudo install -Dm755 "$$f" /usr/lib/owlry/plugins/$$(basename "$$f"); \ done - @for f in target/release/libowlry_lua.so target/release/libowlry_rune.so; do \ - [ -f "$$f" ] && sudo install -Dm755 "$$f" /usr/lib/owlry/runtimes/$$(basename "$$f"); \ - done - @echo "Installed all plugins and runtimes" + @echo "Installed all plugins"