From 3b621cbb997285b1c741fe4ab2d1160cef1cba9d Mon Sep 17 00:00:00 2001 From: ymote <151983+ymote@users.noreply.github.com> Date: Sat, 26 Sep 2026 10:06:41 -0700 Subject: [PATCH 01/10] Host Octoscript mini apps with scoped Matrix and shared Octos services --- Cargo.lock | 7241 +++++++++++++---- Cargo.toml | 76 +- crates/article-core/Cargo.toml | 2 +- crates/article-makepad/Cargo.toml | 4 +- crates/miniapp-core/Cargo.lock | 107 + crates/miniapp-core/Cargo.toml | 13 + crates/miniapp-core/LICENSE-MIT | 9 + crates/miniapp-core/src/lib.rs | 226 + crates/miniapp-core/src/matrix.rs | 757 ++ .../0005-octoscript-miniapps-matrix-octos.md | 118 + examples/miniapps/README.md | 40 + .../miniapps/matrix-octos-script/main.splash | 35 + .../matrix-octos-script/manifest.json | 20 + examples/miniapps/matrix-octos/bindings.json | 6 + examples/miniapps/matrix-octos/kit/LICENSE | 21 + .../matrix-octos/kit/_derive.octoscript | 47 + .../matrix-octos/kit/_derive_color.octoscript | 109 + .../miniapps/matrix-octos/kit/_kit.octoscript | 928 +++ .../matrix-octos/kit/_palette_dark.octoscript | 215 + .../kit/_palette_light.octoscript | 71 + examples/miniapps/matrix-octos/manifest.json | 18 + examples/miniapps/matrix-octos/page.card | 22 + examples/miniapps/matrix-octos/page.data.json | 1 + src/app.rs | 22 + src/home/home_screen.rs | 1 + src/home/mobile.rs | 3 + src/home/navigation_tab_bar.rs | 5 + src/lib.rs | 1 + src/octoscript_apps/matrix/account.rs | 95 + src/octoscript_apps/matrix/membership.rs | 133 + src/octoscript_apps/matrix/mod.rs | 1070 +++ src/octoscript_apps/matrix/policy.rs | 141 + src/octoscript_apps/matrix/room.rs | 608 ++ src/octoscript_apps/matrix/rooms.rs | 166 + src/octoscript_apps/matrix/send.rs | 317 + src/octoscript_apps/matrix/spaces.rs | 132 + src/octoscript_apps/mod.rs | 43 + src/octoscript_apps/octos.rs | 355 + src/octoscript_apps/package.rs | 358 + src/octoscript_apps/ui.rs | 633 ++ src/settings/app_preferences.rs | 4 + src/sliding_sync.rs | 4 + tools/miniapp-package/Cargo.lock | 185 + tools/miniapp-package/Cargo.toml | 8 + tools/miniapp-package/src/main.rs | 27 + 45 files changed, 12615 insertions(+), 1782 deletions(-) create mode 100644 crates/miniapp-core/Cargo.lock create mode 100644 crates/miniapp-core/Cargo.toml create mode 100644 crates/miniapp-core/LICENSE-MIT create mode 100644 crates/miniapp-core/src/lib.rs create mode 100644 crates/miniapp-core/src/matrix.rs create mode 100644 docs/adr/0005-octoscript-miniapps-matrix-octos.md create mode 100644 examples/miniapps/README.md create mode 100644 examples/miniapps/matrix-octos-script/main.splash create mode 100644 examples/miniapps/matrix-octos-script/manifest.json create mode 100644 examples/miniapps/matrix-octos/bindings.json create mode 100644 examples/miniapps/matrix-octos/kit/LICENSE create mode 100644 examples/miniapps/matrix-octos/kit/_derive.octoscript create mode 100644 examples/miniapps/matrix-octos/kit/_derive_color.octoscript create mode 100644 examples/miniapps/matrix-octos/kit/_kit.octoscript create mode 100644 examples/miniapps/matrix-octos/kit/_palette_dark.octoscript create mode 100644 examples/miniapps/matrix-octos/kit/_palette_light.octoscript create mode 100644 examples/miniapps/matrix-octos/manifest.json create mode 100644 examples/miniapps/matrix-octos/page.card create mode 100644 examples/miniapps/matrix-octos/page.data.json create mode 100644 src/octoscript_apps/matrix/account.rs create mode 100644 src/octoscript_apps/matrix/membership.rs create mode 100644 src/octoscript_apps/matrix/mod.rs create mode 100644 src/octoscript_apps/matrix/policy.rs create mode 100644 src/octoscript_apps/matrix/room.rs create mode 100644 src/octoscript_apps/matrix/rooms.rs create mode 100644 src/octoscript_apps/matrix/send.rs create mode 100644 src/octoscript_apps/matrix/spaces.rs create mode 100644 src/octoscript_apps/mod.rs create mode 100644 src/octoscript_apps/octos.rs create mode 100644 src/octoscript_apps/package.rs create mode 100644 src/octoscript_apps/ui.rs create mode 100644 tools/miniapp-package/Cargo.lock create mode 100644 tools/miniapp-package/Cargo.toml create mode 100644 tools/miniapp-package/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index ecc6bbb1..64b68c96 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5,7 +5,7 @@ version = 4 [[package]] name = "ab_glyph_rasterizer" version = "0.1.8" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "accessory" @@ -19,12 +19,30 @@ dependencies = [ "syn 2.0.119", ] +[[package]] +name = "addr2line" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" +dependencies = [ + "gimli", +] + [[package]] name = "adler2" version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" +[[package]] +name = "adobe-cmap-parser" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae8abfa9a4688de8fc9f42b3f013b6fffec18ed8a554f5f113577e0b9b3212a3" +dependencies = [ + "pom", +] + [[package]] name = "aead" version = "0.5.2" @@ -81,6 +99,56 @@ dependencies = [ "subtle", ] +[[package]] +name = "agent-client-protocol" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d386d6a58f4dbe0ebfa98e915caa54005dabdefd419de3d4678b28cd5752444" +dependencies = [ + "agent-client-protocol-derive", + "agent-client-protocol-schema", + "async-io", + "async-process", + "blocking", + "futures", + "futures-concurrency", + "rustc-hash 2.1.1", + "rustix", + "schemars 1.1.0", + "serde", + "serde_json", + "shell-words", + "tracing", + "uuid", + "windows-sys 0.61.1", +] + +[[package]] +name = "agent-client-protocol-derive" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b94934d118a69e921d14e94d4af5b3076563318c52662c89a0ecb3f139e1da" +dependencies = [ + "quote", + "syn 2.0.119", +] + +[[package]] +name = "agent-client-protocol-schema" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06679e1542356341f4550ccfb16338b64f37f6af70de2105446ef6fbb078234c" +dependencies = [ + "anyhow", + "derive_more 2.0.1", + "schemars 1.1.0", + "serde", + "serde_json", + "serde_with", + "strum", + "tracing", +] + [[package]] name = "aho-corasick" version = "1.1.3" @@ -105,6 +173,23 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "android_log-sys" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84521a3cf562bc62942e294181d9eef17eb38ceb8c68677bc49f144e4c3d4f8d" + +[[package]] +name = "android_logger" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05b07e8e73d720a1f2e4b6014766e6039fd2e96a4fa44e2a78d0e1fa2ff49826" +dependencies = [ + "android_log-sys", + "env_filter 0.1.4", + "log", +] + [[package]] name = "android_system_properties" version = "0.1.5" @@ -114,11 +199,28 @@ dependencies = [ "libc", ] +[[package]] +name = "anndists" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8396b473aa0bceed68fb32462505387ea39fa47c7029417e0a49f10592b036" +dependencies = [ + "anyhow", + "cfg-if 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cpu-time", + "env_logger", + "lazy_static", + "log", + "num-traits 0.2.19", + "num_cpus", + "rayon", +] + [[package]] name = "anstream" -version = "0.6.20" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ae563653d1938f79b1ab1b5e668c87c76a9930414574a6583a7b7e11a8e6192" +checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" dependencies = [ "anstyle", "anstyle-parse", @@ -131,15 +233,15 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.11" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" [[package]] name = "anstyle-parse" -version = "0.2.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" +checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e" dependencies = [ "utf8parse", ] @@ -215,6 +317,15 @@ dependencies = [ "serde", ] +[[package]] +name = "arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" +dependencies = [ + "derive_arbitrary", +] + [[package]] name = "arboard" version = "3.6.1" @@ -237,9 +348,12 @@ dependencies = [ [[package]] name = "arc-swap" -version = "1.7.1" +version = "1.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" +checksum = "c049c0be4daef0b145cb3555416b3b8ef5b7888a38aea1a3a155801fe7b0810b" +dependencies = [ + "rustversion", +] [[package]] name = "archery" @@ -284,7 +398,7 @@ checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" [[package]] name = "arrayvec" version = "0.7.6" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "arrayvec" @@ -328,10 +442,16 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9dbc3a507a82b17ba0d98f6ce8fd6954ea0c8152e98009d36a40d8dcc8ce078a" +[[package]] +name = "ascii" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d92bec98840b8f03a5ff5413de5293bfcd8bf96467cf5452609f939ec6f5de16" + [[package]] name = "ash" version = "0.38.0+1.3.281" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "libloading 0.8.9", ] @@ -607,6 +727,23 @@ dependencies = [ "syn 3.0.3", ] +[[package]] +name = "async-tungstenite" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8acc405d38be14342132609f06f02acaf825ddccfe76c4824a69281e0458ebd4" +dependencies = [ + "atomic-waker", + "futures-core", + "futures-io", + "futures-task", + "futures-util", + "log", + "pin-project-lite", + "tokio", + "tungstenite 0.28.0", +] + [[package]] name = "async_cell" version = "0.2.3" @@ -675,6 +812,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "31b698c5f9a010f6573133b09e0de5408834d0c82f8d7475a89fc1867a71cd90" dependencies = [ "axum-core", + "base64 0.22.1", "bytes", "form_urlencoded", "futures-util", @@ -687,14 +825,17 @@ dependencies = [ "matchit", "memchr 2.7.6 (registry+https://github.com/rust-lang/crates.io-index)", "mime", + "multer", "percent-encoding", "pin-project-lite", "serde_core", "serde_json", "serde_path_to_error", "serde_urlencoded", + "sha1", "sync_wrapper", "tokio", + "tokio-tungstenite 0.29.0", "tower", "tower-layer", "tower-service", @@ -731,6 +872,21 @@ dependencies = [ "tokio", ] +[[package]] +name = "backtrace" +version = "0.3.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" +dependencies = [ + "addr2line", + "cfg-if 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-link 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "base16ct" version = "0.2.0" @@ -808,9 +964,9 @@ dependencies = [ [[package]] name = "bit-set" version = "0.8.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ - "bit-vec 0.8.0 (git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4)", + "bit-vec 0.8.0 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", ] [[package]] @@ -822,7 +978,7 @@ checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" [[package]] name = "bit-vec" version = "0.8.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "bitflags" @@ -833,7 +989,7 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" version = "2.10.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "bitflags" @@ -877,7 +1033,7 @@ dependencies = [ "arrayvec 0.7.8", "cc", "cfg-if 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "constant_time_eq", + "constant_time_eq 0.4.2", "cpufeatures 0.3.0", ] @@ -894,13 +1050,13 @@ dependencies = [ "cssparser", "cursor-icon", "debug_timer 0.1.3 (git+https://github.com/OctoSense-org/makepad-html?rev=b16565ae1e56dd7c3a87f00455ae327df599ca3b)", - "euclid", + "euclid 0.22.14", "html-escape", "image", "keyboard-types", "kurbo", "linebender_resource_handle", - "markup5ever", + "markup5ever 0.39.0", "objc2", "parley", "percent-encoding", @@ -928,8 +1084,8 @@ source = "git+https://github.com/OctoSense-org/makepad-html?rev=b16565ae1e56dd7c dependencies = [ "blitz-dom", "blitz-traits", - "html5ever", - "xml5ever", + "html5ever 0.39.0", + "xml5ever 0.39.0", ] [[package]] @@ -941,7 +1097,7 @@ dependencies = [ "blitz-dom", "blitz-traits", "color", - "euclid", + "euclid 0.22.14", "kurbo", "parley", "peniko", @@ -1069,16 +1225,33 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "bstr" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bb31b46c14244e20ee9984b11bf5c992b91fb6939fea616e3512c8baecdbe5f" +dependencies = [ + "memchr 2.7.6 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-automata", + "serde_core", +] + [[package]] name = "bumpalo" version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" +[[package]] +name = "bytecount" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "175812e0be2bccb6abe50bb8d566126198344f707e304f45c648fd8f2cc0365e" + [[package]] name = "bytemuck" version = "1.25.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "bytemuck" @@ -1109,7 +1282,7 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "byteorder" version = "1.5.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "byteorder-lite" @@ -1122,6 +1295,9 @@ name = "bytes" version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" +dependencies = [ + "serde", +] [[package]] name = "bytesize" @@ -1129,6 +1305,25 @@ version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7354288c522e7e980fafd2075d63d1285794c3a6a16cdd492f189ea406e5f18b" +[[package]] +name = "bzip2" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49ecfb22d906f800d4fe833b6282cf4dc1c298f5057ca0b5445e5c209735ca47" +dependencies = [ + "bzip2-sys", +] + +[[package]] +name = "bzip2-sys" +version = "0.1.13+1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225bff33b2141874fe80d71e07d6eec4f85c5c216453dd96388240f96e1acc14" +dependencies = [ + "cc", + "pkg-config 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "caseless" version = "0.2.2" @@ -1180,9 +1375,15 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" dependencies = [ - "nom", + "nom 7.1.3", ] +[[package]] +name = "cff-parser" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31f5b6e9141c036f3ff4ce7b2f7e432b0f00dee416ddcd4f17741d189ddc2e9d" + [[package]] name = "cfg-if" version = "1.0.4" @@ -1192,7 +1393,7 @@ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "cfg-if" version = "1.0.4" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "cfg_aliases" @@ -1203,7 +1404,7 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "cfg_aliases" version = "0.2.1" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "chacha20" @@ -1253,6 +1454,71 @@ dependencies = [ "poly1305 0.9.1", ] +[[package]] +name = "chromiumoxide" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26ed067eb6c1f660bdb87c05efb964421d2ca262bae0296cdfe38cf0cd949a3e" +dependencies = [ + "async-tungstenite", + "base64 0.22.1", + "bytes", + "chromiumoxide_cdp", + "chromiumoxide_types", + "dunce", + "fnv", + "futures", + "futures-timer", + "pin-project-lite", + "reqwest 0.13.2", + "serde", + "serde_json", + "thiserror 2.0.20", + "tokio", + "tracing", + "url", + "which 8.0.6", + "windows-registry 0.6.1", +] + +[[package]] +name = "chromiumoxide_cdp" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68a6a03a7ebac4ea85308f285d6959a3e6b2ce32a0c9465dc7a7b1db0144eec7" +dependencies = [ + "chromiumoxide_pdl", + "chromiumoxide_types", + "serde", + "serde_json", +] + +[[package]] +name = "chromiumoxide_pdl" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c602dea92337bc4d824668d78c5b79c3b4ddb29b40dd7218282bbe8fd3fc2091" +dependencies = [ + "chromiumoxide_types", + "either", + "heck", + "once_cell 1.21.4", + "proc-macro2", + "quote", + "regex", + "serde_json", +] + +[[package]] +name = "chromiumoxide_types" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678d5146e74f16fc4a41978b275af572cd913de1f10270d2b93b6c276bc57d80" +dependencies = [ + "serde", + "serde_json", +] + [[package]] name = "chrono" version = "0.4.45" @@ -1267,6 +1533,22 @@ dependencies = [ "windows-link 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "chrono-tz" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6139a8597ed92cf816dfb33f5dd6cf0bb93a6adc938f11039f371bc5bcd26c3" +dependencies = [ + "chrono", + "phf 0.12.1", +] + +[[package]] +name = "chunked_transfer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e4de3bc4ea267985becf712dc6d9eed8b04c953b3fcfb339ebc87acd9804901" + [[package]] name = "ciborium" version = "0.2.2" @@ -1329,9 +1611,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.48" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2134bb3ea021b78629caa971416385309e0131b351b25e01dc16fb54e1b5fae" +checksum = "aa8876b300ab35ba921adea3dfd70157a46249b33f95c9084ae5709785478946" dependencies = [ "clap_builder", "clap_derive", @@ -1339,9 +1621,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.48" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2ba64afa3c0a6df7fa517765e31314e983f51dda798ffba27b988194fb65dc9" +checksum = "ec0797fb7aeb1406c84efac526901f7ec3ead2124f946b494e72879d4b54704d" dependencies = [ "anstream", "anstyle", @@ -1349,23 +1631,32 @@ dependencies = [ "strsim", ] +[[package]] +name = "clap_complete" +version = "4.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037e2a1a92236d0aff7e845093f64661d6df4c02c9fcc61a60e9e1d736fa392f" +dependencies = [ + "clap", +] + [[package]] name = "clap_derive" -version = "4.5.47" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbfd7eae0b0f1a6e63d4b13c9c478de77c2eb546fba158ad50b4203dc24b9f9c" +checksum = "f9c751b79415d4e559e3d1fcf128e09e720eb673a06d26cf6f392d37d75b66e0" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.119", + "syn 3.0.3", ] [[package]] name = "clap_lex" -version = "0.7.5" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" +checksum = "1c133bc6a41be0d194c306b5506d15e6feeea7b1d6604bd3f8310dfb2ca96486" [[package]] name = "clipboard-win" @@ -1376,6 +1667,15 @@ dependencies = [ "error-code", ] +[[package]] +name = "clru" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "197fd99cb113a8d5d9b6376f3aa817f32c1078f2343b714fff7d2ca44fdf67d5" +dependencies = [ + "hashbrown 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "cmake" version = "0.1.54" @@ -1400,6 +1700,33 @@ dependencies = [ "bytemuck 1.25.2", ] +[[package]] +name = "color-eyre" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5920befb47832a6d61ee3a3a846565cfa39b331331e68a3b1d1116630f2f26d" +dependencies = [ + "backtrace", + "color-spantrace", + "eyre", + "indenter", + "once_cell 1.21.4", + "owo-colors", + "tracing-error", +] + +[[package]] +name = "color-spantrace" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8b88ea9df13354b55bc7234ebcce36e6ef896aca2e42a15de9e10edce01b427" +dependencies = [ + "once_cell 1.21.4", + "owo-colors", + "tracing-core", + "tracing-error", +] + [[package]] name = "color_quant" version = "1.1.0" @@ -1412,6 +1739,16 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" +[[package]] +name = "colored" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c" +dependencies = [ + "lazy_static", + "windows-sys 0.59.0", +] + [[package]] name = "combine" version = "4.6.7" @@ -1486,6 +1823,12 @@ dependencies = [ "typewit", ] +[[package]] +name = "constant_time_eq" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" + [[package]] name = "constant_time_eq" version = "0.4.2" @@ -1546,8 +1889,18 @@ dependencies = [ ] [[package]] -name = "cpubits" -version = "0.1.1" +name = "cpu-time" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9e393a7668fe1fad3075085b86c781883000b4ede868f43627b34a87c8b7ded" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "cpubits" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "15b85f9c39137c3a891689859392b1bd49812121d0d61c9caf00d46ed5ce06ae" @@ -1593,6 +1946,17 @@ dependencies = [ "cfg-if 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "cron" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5877d3fbf742507b66bc2a1945106bd30dd8504019d596901ddd012a4dd01740" +dependencies = [ + "chrono", + "once_cell 1.21.4", + "winnow 0.6.26", +] + [[package]] name = "crossbeam-channel" version = "0.5.15" @@ -1645,7 +2009,7 @@ checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" [[package]] name = "crunchy" version = "0.2.4" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "crypto-bigint" @@ -1836,12 +2200,22 @@ dependencies = [ [[package]] name = "darling" -version = "0.21.3" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" +dependencies = [ + "darling_core 0.23.0", + "darling_macro 0.23.0", +] + +[[package]] +name = "darling" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" +checksum = "ed17f5901b6630b993ca003def43f2f8ef4014fc13b047b57aad617ff32bc2ec" dependencies = [ - "darling_core 0.21.3", - "darling_macro 0.21.3", + "darling_core 0.24.1", + "darling_macro 0.24.1", ] [[package]] @@ -1859,11 +2233,10 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.21.3" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4" +checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0" dependencies = [ - "fnv", "ident_case", "proc-macro2", "quote", @@ -1871,6 +2244,19 @@ dependencies = [ "syn 2.0.119", ] +[[package]] +name = "darling_core" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6837e2cf7485aaae18f86181d2f0e9a7ed297a025e220aeabf63fdebd3a2ddff" +dependencies = [ + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 3.0.3", +] + [[package]] name = "darling_macro" version = "0.20.11" @@ -1884,15 +2270,40 @@ dependencies = [ [[package]] name = "darling_macro" -version = "0.21.3" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" +checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" dependencies = [ - "darling_core 0.21.3", + "darling_core 0.23.0", "quote", "syn 2.0.119", ] +[[package]] +name = "darling_macro" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ac7135c3ef02b2f7833bbeb1be5ba7f966dcde8a87c6b87f65a778d71a02785" +dependencies = [ + "darling_core 0.24.1", + "quote", + "syn 3.0.3", +] + +[[package]] +name = "dashmap" +version = "6.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6361d5c062261c78a176addb82d4c821ae42bed6089de0e12603cd25de2059c" +dependencies = [ + "cfg-if 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils", + "hashbrown 0.14.5", + "lock_api", + "once_cell 1.21.4", + "parking_lot_core", +] + [[package]] name = "data-encoding" version = "2.9.0" @@ -1957,6 +2368,43 @@ version = "3.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a9244323129647178bf41ac861a2cdb9d9c81b9b09d3d0d1de9cd302b33b8a1d" +[[package]] +name = "deflate64" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac6b926516df9c60bfa16e107b21086399f8285a44ca9711344b9e553c5146e2" + +[[package]] +name = "defmt" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2953bfe4f93bbd20cc71198842756f77d161884c99ebbabc41d80231ded88d1" +dependencies = [ + "bitflags 1.3.2", + "defmt-macros", +] + +[[package]] +name = "defmt-macros" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bad9c72e7ca2137e0dc3813245a0d282fd6daad32fd800af018306a9169b5fe8" +dependencies = [ + "defmt-parser", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "defmt-parser" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e" +dependencies = [ + "thiserror 2.0.20", +] + [[package]] name = "delegate-display" version = "3.0.0" @@ -2002,6 +2450,17 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "derive_arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + [[package]] name = "derive_more" version = "1.0.0" @@ -2087,6 +2546,27 @@ dependencies = [ "ctutils", ] +[[package]] +name = "dirs" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +dependencies = [ + "dirs-sys 0.4.1", +] + +[[package]] +name = "dirs-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +dependencies = [ + "libc", + "option-ext", + "redox_users 0.4.6", + "windows-sys 0.48.0", +] + [[package]] name = "dirs-sys" version = "0.5.0" @@ -2095,7 +2575,7 @@ checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" dependencies = [ "libc", "option-ext", - "redox_users", + "redox_users 0.5.2", "windows-sys 0.61.1", ] @@ -2140,7 +2620,7 @@ checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" [[package]] name = "downcast-rs" version = "1.2.1" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "dtoa" @@ -2169,6 +2649,15 @@ version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" +[[package]] +name = "ecb" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a8bfa975b1aec2145850fcaa1c6fe269a16578c44705a532ae3edc92b8881c7" +dependencies = [ + "cipher 0.4.4", +] + [[package]] name = "ecdsa" version = "0.16.9" @@ -2261,6 +2750,22 @@ dependencies = [ "zeroize", ] +[[package]] +name = "email-encoding" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "420b9da095f052ea597503e39073b5b3c522f7db933fbac202d91d24492693fd" +dependencies = [ + "base64 0.23.1", + "memchr 2.7.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "email_address" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e079f19b08ca6239f47f8ba8509c11cf3ea30095831f7fed61441475edd8c449" + [[package]] name = "emojis" version = "0.9.0" @@ -2285,12 +2790,30 @@ version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "66b7e2430c6dff6a955451e2cfc438f09cea1965a9d6f87f7e3b90decc014099" +[[package]] +name = "endian-type" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" + [[package]] name = "entities" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5320ae4c3782150d900b79807611a59a99fc9a1d61d686faafc24b93fc8d7ca" +[[package]] +name = "enum-as-inner" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.119", +] + [[package]] name = "enumflags2" version = "0.7.12" @@ -2312,6 +2835,45 @@ dependencies = [ "syn 2.0.119", ] +[[package]] +name = "env_filter" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bf3c259d255ca70051b30e2e95b5446cdb8949ac4cd22c0d7fd634d89f568e2" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_filter" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "900d271a03799a1ee8d1ca9b19893b48ca674a9284fefcfb85f05e74ed314217" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_home" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7f84e12ccf0a7ddc17a6c41c93326024c42920d7ee630d04950e6926645c0fe" + +[[package]] +name = "env_logger" +version = "0.11.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de671bd27a75a797dc9ae289ba1e77276e75e2026408aab65185384e2d5cd3f6" +dependencies = [ + "anstream", + "anstyle", + "env_filter 2.0.0", + "jiff", + "log", +] + [[package]] name = "equivalent" version = "1.0.2" @@ -2321,7 +2883,7 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "equivalent" version = "1.0.2" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "errno" @@ -2350,6 +2912,15 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "euclid" +version = "0.20.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bb7ef65b3777a325d1eeefefab5b6d4959da54747e33bd6258e789640f307ad" +dependencies = [ + "num-traits 0.2.19", +] + [[package]] name = "euclid" version = "0.22.14" @@ -2420,6 +2991,17 @@ dependencies = [ "smallvec 1.15.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "eyre" +version = "0.6.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08309dbcc659c5549a24ddb9b27027640641b282ef5768267c7e675558986a3" +dependencies = [ + "autocfg", + "indenter", + "once_cell 1.21.4", +] + [[package]] name = "fallible-iterator" version = "0.3.0" @@ -2455,11 +3037,21 @@ dependencies = [ "syn 2.0.119", ] +[[package]] +name = "faster-hex" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7223ae2d2f179b803433d9c830478527e92b8117eab39460edae7f1614d9fb73" +dependencies = [ + "heapless", + "serde", +] + [[package]] name = "fastrand" -version = "2.3.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223" [[package]] name = "fax" @@ -2467,6 +3059,17 @@ version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "caf1079563223d5d59d83c85886a56e586cfd5c1a26292e971a0fa266531ac5a" +[[package]] +name = "fd-lock" +version = "4.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce92ff622d6dadf7349484f42c93271a0d49b7cc4d466a936405bacbe10aa78" +dependencies = [ + "cfg-if 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "rustix", + "windows-sys 0.59.0", +] + [[package]] name = "fdeflate" version = "0.3.7" @@ -2504,6 +3107,16 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64cd1e32ddd350061ae6edb1b082d7c54915b5c672c389143b9a63403a109f24" +[[package]] +name = "filetime" +version = "0.2.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c287a33c7f0a620c38e641e7f60827713987b3c0f26e8ddc9462cc69cf75759" +dependencies = [ + "cfg-if 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", +] + [[package]] name = "find-msvc-tools" version = "0.1.2" @@ -2516,6 +3129,12 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "80bb028c8b4148c9ee0cca68fcd9add6044e81d3619f48577ddf13a263d047a2" +[[package]] +name = "fixedbitset" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" + [[package]] name = "flate2" version = "1.1.2" @@ -2564,7 +3183,7 @@ checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" [[package]] name = "foldhash" version = "0.2.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "font-types" @@ -2644,17 +3263,46 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fs-err" +version = "3.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b91aa448ca50d7e79433bdf3ee8d99215430d2ec02ade5aefab2a073a1822e8a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "fs2" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "fs_extra" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" +[[package]] +name = "futf" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843" +dependencies = [ + "mac", + "new_debug_unreachable", +] + [[package]] name = "futures" -version = "0.3.31" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +checksum = "9a31d2a3fbaaeb2af2368bbdd904aa8e812d3c04a1ee10d3171f52d556e5d0a3" dependencies = [ "futures-channel", "futures-core", @@ -2675,6 +3323,19 @@ dependencies = [ "futures-sink", ] +[[package]] +name = "futures-concurrency" +version = "7.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "175cd8cca9e1d45b87f18ffa75088f2099e3c4fe5e2f83e42de112560bea8ea6" +dependencies = [ + "fixedbitset", + "futures-core", + "futures-lite", + "pin-project", + "smallvec 1.15.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "futures-core" version = "0.3.34" @@ -2745,6 +3406,12 @@ version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd417de3d1d015fc3bfd2b1ea46dfc7bab72ef86f1cc7cc9c78e728b34a6d1fd" +[[package]] +name = "futures-timer" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af43fadb8a98512d547e37b4e92e0ced13e205c061b87b4623eff01d918d6968" + [[package]] name = "futures-util" version = "0.3.34" @@ -2774,9 +3441,9 @@ dependencies = [ [[package]] name = "fxhash" version = "0.2.1" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ - "byteorder 1.5.0 (git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4)", + "byteorder 1.5.0 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", ] [[package]] @@ -2913,2534 +3580,4375 @@ dependencies = [ ] [[package]] -name = "glifo" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed4a1bb24121291d27230c1b1b44e07d6a9b28cefdb32fe1581dfb84e14f940a" -dependencies = [ - "bytemuck 1.25.2", - "foldhash 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "hashbrown 0.17.1", - "log", - "peniko", - "skrifa", +name = "gimli" +version = "0.32.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" + +[[package]] +name = "gix" +version = "0.79.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c66adef5e4d836ad08bf424dce5e3eb18f51544eee702860419295120dd48811" +dependencies = [ + "gix-actor", + "gix-attributes", + "gix-command", + "gix-commitgraph", + "gix-config", + "gix-date", + "gix-diff", + "gix-discover", + "gix-error", + "gix-features", + "gix-filter", + "gix-fs", + "gix-glob", + "gix-hash", + "gix-hashtable", + "gix-ignore", + "gix-index", + "gix-lock", + "gix-object", + "gix-odb", + "gix-pack", + "gix-path", + "gix-pathspec", + "gix-protocol", + "gix-ref", + "gix-refspec", + "gix-revision", + "gix-revwalk", + "gix-sec", + "gix-shallow", + "gix-submodule", + "gix-tempfile", + "gix-trace", + "gix-traverse", + "gix-url", + "gix-utils", + "gix-validate", + "gix-worktree", "smallvec 1.15.1 (registry+https://github.com/rust-lang/crates.io-index)", - "vello_common", + "thiserror 2.0.20", ] [[package]] -name = "glob" -version = "0.3.3" +name = "gix-actor" +version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" +checksum = "0c44f13049925e8dc3955c20ecec5391cedfb041e0952416b583ecc57bc68325" +dependencies = [ + "bstr", + "gix-date", + "gix-error", + "winnow 0.7.15", +] [[package]] -name = "gloo-timers" -version = "0.3.0" +name = "gix-attributes" +version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" +checksum = "9e72da5a1c35c9a129be0c60ab9968779981ca50835dd98650ecd8b0ea4d721e" dependencies = [ - "futures-channel", - "futures-core", - "js-sys", - "wasm-bindgen", + "bstr", + "gix-glob", + "gix-path", + "gix-quote", + "gix-trace", + "kstring", + "smallvec 1.15.1 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 2.0.20", + "unicode-bom", ] [[package]] -name = "gloo-timers" -version = "0.4.0" +name = "gix-bitmap" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "482ce8a491a501da4cd806bd190275363d674f2845005c6ddbd5d3e1dd54495d" +checksum = "d982fc7ef0608e669851d0d2a6141dae74c60d5a27e8daa451f2a4857bbf41e2" dependencies = [ - "futures-channel", - "futures-core", - "js-sys", - "wasm-bindgen", + "thiserror 2.0.20", ] [[package]] -name = "gloo-utils" -version = "0.3.0" +name = "gix-chunk" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4202275d95a142fa209a1e35e91c250a710c5600731372cd3464a39ed01573d6" +checksum = "d14ee09ab454481a91fe969ca5afbd41c8a9b05680197b6554ebb69bdcf7d571" dependencies = [ - "js-sys", - "serde", - "serde_json", - "wasm-bindgen", - "web-sys", + "gix-error", ] [[package]] -name = "group" -version = "0.13.0" +name = "gix-command" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +checksum = "2962172c6f78731e2b7773bf762f7b8d1746a342a4c0a8914a612206e1295953" dependencies = [ - "ff", - "rand_core 0.6.4", - "subtle", + "bstr", + "gix-path", + "gix-quote", + "gix-trace", + "shell-words", ] [[package]] -name = "growable-bloom-filter" -version = "2.1.1" +name = "gix-commitgraph" +version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d174ccb4ba660d431329e7f0797870d0a4281e36353ec4b4a3c5eab6c2cfb6f1" +checksum = "f9dc2a550978b510b4e58b0bf5a15481433c3b21981330f3898d93f25b07d9a5" dependencies = [ - "serde", - "serde_bytes", - "serde_derive", - "xxhash-rust", + "bstr", + "gix-chunk", + "gix-error", + "gix-hash", + "memmap2", ] [[package]] -name = "guillotiere" -version = "0.7.0" +name = "gix-config" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b17e70c989c36bad147b27a58d148c0741c51448aa5653436547323e524d0ab" +checksum = "db778c8703f3c7f687e03ce22ac8f6eac02adbdafae4cb19d541126fa012524f" dependencies = [ - "euclid", + "bstr", + "gix-config-value", + "gix-features", + "gix-glob", + "gix-path", + "gix-ref", + "gix-sec", + "memchr 2.7.6 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 1.15.1 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 2.0.20", + "unicode-bom", + "winnow 0.7.15", ] [[package]] -name = "h2" -version = "0.4.12" +name = "gix-config-value" +version = "0.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386" +checksum = "4378c53ec3db049919edf91ff76f56f28886a8b4b4a5a9dc633108d84afc3675" dependencies = [ - "atomic-waker", - "bytes", - "fnv", - "futures-core", - "futures-sink", - "http", - "indexmap 2.14.2", - "slab", - "tokio", - "tokio-util", - "tracing", + "bitflags 2.13.1", + "bstr", + "gix-path", + "libc", + "thiserror 2.0.20", ] [[package]] -name = "half" -version = "2.7.1" +name = "gix-date" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" +checksum = "e66a5117b22495fe7cb4b443777cf3f024a1b1db0009771db440fc8b38a0a6fd" dependencies = [ - "cfg-if 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "crunchy 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", - "zerocopy 0.8.27", + "bstr", + "gix-error", + "itoa", + "jiff", + "smallvec 1.15.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "harfrust" -version = "0.12.0" +name = "gix-diff" +version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c03d949a14aa089bbb282f7dd76a498a7f684428e4257202efc119ec010376f9" +checksum = "ebee256b21a7d46cec85ab84e824742142a23a21111556a5e50c15796110c6c6" dependencies = [ - "bitflags 2.13.1", - "bytemuck 1.25.2", - "read-fonts", - "smallvec 1.15.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bstr", + "gix-command", + "gix-filter", + "gix-fs", + "gix-hash", + "gix-object", + "gix-path", + "gix-tempfile", + "gix-trace", + "gix-traverse", + "gix-worktree", + "imara-diff", + "thiserror 2.0.20", ] [[package]] -name = "hashbrown" -version = "0.12.3" +name = "gix-discover" +version = "0.47.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +checksum = "93103d88576e048a681ebee83e93162972cd4cbce1485a6137cfc98fc0ba152d" +dependencies = [ + "bstr", + "dunce", + "gix-fs", + "gix-path", + "gix-ref", + "gix-sec", + "thiserror 2.0.20", +] [[package]] -name = "hashbrown" -version = "0.15.5" +name = "gix-error" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +checksum = "92e37b10e97c822fc17550fc1a187283ad3ce79617e920bf179f301ee12abcbc" dependencies = [ - "allocator-api2", - "equivalent 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "foldhash 0.1.5", + "bstr", ] [[package]] -name = "hashbrown" -version = "0.16.1" +name = "gix-features" +version = "0.46.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +checksum = "752493cd4b1d5eaaa0138a7493f65c96863fefa990fc021e0e519579e389ab20" dependencies = [ - "allocator-api2", - "equivalent 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "foldhash 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crc32fast", + "crossbeam-channel", + "gix-path", + "gix-trace", + "gix-utils", + "libc", + "once_cell 1.21.4", + "parking_lot", + "prodash", + "thiserror 2.0.20", + "walkdir", + "zlib-rs", ] [[package]] -name = "hashbrown" -version = "0.16.1" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +name = "gix-filter" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "094253121df9aa1cb46d1da0200dd63ebf16263a35f03295109978bf7ed2b483" dependencies = [ - "foldhash 0.2.0 (git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4)", + "bstr", + "encoding_rs", + "gix-attributes", + "gix-command", + "gix-hash", + "gix-object", + "gix-packetline", + "gix-path", + "gix-quote", + "gix-trace", + "gix-utils", + "smallvec 1.15.1 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 2.0.20", ] [[package]] -name = "hashbrown" -version = "0.17.1" +name = "gix-fs" +version = "0.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" +checksum = "a964b4aec683eb0bacb87533defa80805bb4768056371a47ab38b00a2d377b72" dependencies = [ - "foldhash 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bstr", + "fastrand", + "gix-features", + "gix-path", + "gix-utils", + "thiserror 2.0.20", ] [[package]] -name = "hashlink" -version = "0.10.0" +name = "gix-glob" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" +checksum = "b03e6cd88cc0dc1eafa1fddac0fb719e4e74b6ea58dd016e71125fde4a326bee" dependencies = [ - "hashbrown 0.15.5", + "bitflags 2.13.1", + "bstr", + "gix-features", + "gix-path", ] [[package]] -name = "hashlink" -version = "0.12.2" +name = "gix-hash" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a596f1b20ed2cc5ecac41a164aaebc7258057060f06c0cf7a2ba3991ee7990fb" +checksum = "d8ced05d2d7b13bff08b2f7eb4e47cfeaf00b974c2ddce08377c4fe1f706b3eb" dependencies = [ - "hashbrown 0.17.1", + "faster-hex", + "gix-features", + "sha1-checked", + "thiserror 2.0.20", ] [[package]] -name = "heck" -version = "0.5.0" +name = "gix-hashtable" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +checksum = "52f1eecdd006390cbed81f105417dbf82a6fe40842022006550f2e32484101da" +dependencies = [ + "gix-hash", + "hashbrown 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot", +] [[package]] -name = "hermit-abi" -version = "0.5.2" +name = "gix-ignore" +version = "0.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" +checksum = "09f915dcf6911e3027537166d34e13f0fe101ed12225178d2ae29cd1272cff26" +dependencies = [ + "bstr", + "gix-glob", + "gix-path", + "gix-trace", + "unicode-bom", +] [[package]] -name = "hex" -version = "0.4.3" +name = "gix-index" +version = "0.47.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +checksum = "ea450ed666a39676d7e9a41b899487d1645d88053bc8c8cecfca0cf96fcd4a03" +dependencies = [ + "bitflags 2.13.1", + "bstr", + "filetime", + "fnv", + "gix-bitmap", + "gix-features", + "gix-fs", + "gix-hash", + "gix-lock", + "gix-object", + "gix-traverse", + "gix-utils", + "gix-validate", + "hashbrown 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa", + "libc", + "memmap2", + "rustix", + "smallvec 1.15.1 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 2.0.20", +] [[package]] -name = "hexf-parse" -version = "0.2.1" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +name = "gix-lock" +version = "21.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "054fbd0989700c69dc5aa80bc66944f05df1e15aa7391a9e42aca7366337905f" +dependencies = [ + "gix-tempfile", + "gix-utils", + "thiserror 2.0.20", +] [[package]] -name = "hilog-sys" -version = "0.1.8" +name = "gix-object" +version = "0.56.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f715f263b6e73aa2322b59057134b4daf56a765cbebc2f6b35e640ffded3361b" +checksum = "227e12fad42022ff08d6fbcc4bae34d6e2aa180576e9e1106d9a29a06798e750" +dependencies = [ + "bstr", + "gix-actor", + "gix-date", + "gix-features", + "gix-hash", + "gix-hashtable", + "gix-path", + "gix-utils", + "gix-validate", + "itoa", + "smallvec 1.15.1 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 2.0.20", + "winnow 0.7.15", +] [[package]] -name = "hkdf" -version = "0.12.4" +name = "gix-odb" +version = "0.76.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +checksum = "e84f7e115b2b6615f0c5acddc269598ebc539c363fb276dbd242755a1dd7126c" dependencies = [ - "hmac 0.12.1", + "arc-swap", + "gix-features", + "gix-fs", + "gix-hash", + "gix-hashtable", + "gix-object", + "gix-pack", + "gix-path", + "gix-quote", + "parking_lot", + "tempfile", + "thiserror 2.0.20", ] [[package]] -name = "hkdf" -version = "0.13.0" +name = "gix-pack" +version = "0.66.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4aaa26c720c68b866f2c96ef5c1264b3e6f473fe5d4ce61cd44bbe913e553018" +checksum = "dfc20b54d50f64fb02281f2a6c4a24bb9356befdf4535d5a68924575fd67cd5e" dependencies = [ - "hmac 0.13.0", + "clru", + "gix-chunk", + "gix-error", + "gix-features", + "gix-hash", + "gix-hashtable", + "gix-object", + "gix-path", + "memmap2", + "smallvec 1.15.1 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 2.0.20", + "uluru", ] [[package]] -name = "hmac" -version = "0.12.1" +name = "gix-packetline" +version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +checksum = "b217dd0ee0c4021ecf169a4a519b1b4f80d15e3f3765f3dc466223dc0ac891d7" dependencies = [ - "digest 0.10.7", + "bstr", + "faster-hex", + "gix-trace", + "thiserror 2.0.20", ] [[package]] -name = "hmac" -version = "0.13.0" +name = "gix-path" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6303bc9732ae41b04cb554b844a762b4115a61bfaa81e3e83050991eeb56863f" +checksum = "c8fd1fe596dc393b538e1d5492c5585971a9311475b3255f7b889023df208476" dependencies = [ - "digest 0.11.3", + "bstr", + "gix-trace", + "gix-validate", + "thiserror 2.0.20", ] [[package]] -name = "home" -version = "0.5.12" +name = "gix-pathspec" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" +checksum = "c7f4cc23f55ca7c190bf243f1a4e2139d4522022f724fb0dfc06c93f65a01ef6" dependencies = [ - "windows-sys 0.61.1", + "bitflags 2.13.1", + "bstr", + "gix-attributes", + "gix-config-value", + "gix-glob", + "gix-path", + "thiserror 2.0.20", ] [[package]] -name = "hpke" -version = "0.12.0" +name = "gix-protocol" +version = "0.57.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4917627a14198c3603282c5158b815ad5534795451d3c074b53cf3cee0960b11" +checksum = "a13680c03e847d8f32a59cf1511dd05334d429da33f5af08891367680f15cbca" dependencies = [ - "aead 0.5.2", - "aes-gcm", - "chacha20poly1305 0.10.1", - "digest 0.10.7", - "generic-array", - "hkdf 0.12.4", - "hmac 0.12.1", - "p256", - "rand_core 0.6.4", - "sha2 0.10.9", - "subtle", - "x25519-dalek 2.0.1", - "zeroize", + "bstr", + "gix-date", + "gix-features", + "gix-hash", + "gix-ref", + "gix-shallow", + "gix-transport", + "gix-utils", + "maybe-async", + "thiserror 2.0.20", + "winnow 0.7.15", ] [[package]] -name = "hpke" -version = "0.14.1" +name = "gix-quote" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5324110b02044183df000f0bd7d2d7e61f1000631508627e77f63983b6fdffb" +checksum = "96fc2ff2ec8cc0c92807f02eab1f00eb02619fc2810d13dc42679492fcc36757" dependencies = [ - "aead 0.6.1", - "chacha20poly1305 0.11.0", - "getrandom 0.4.3", - "hkdf 0.13.0", - "hybrid-array", - "rand_core 0.10.1", - "sha2 0.11.0", - "subtle", - "x25519-dalek 3.0.0", - "zeroize", + "bstr", + "gix-utils", + "thiserror 2.0.20", ] [[package]] -name = "html-escape" -version = "0.2.15" +name = "gix-ref" +version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9356095b4b41197bba32173600e1582792cda618f65d12f68e2e77d273413c5" +checksum = "c92fd2e86d65efe972a5226f303ed72cfb49a8ad03740e5cc2b27c07970a5d78" +dependencies = [ + "gix-actor", + "gix-features", + "gix-fs", + "gix-hash", + "gix-lock", + "gix-object", + "gix-path", + "gix-tempfile", + "gix-utils", + "gix-validate", + "memmap2", + "thiserror 2.0.20", + "winnow 0.7.15", +] [[package]] -name = "html5ever" -version = "0.39.0" +name = "gix-refspec" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46a1761807faccc9a19e86944bbf40610014066306f96edcdedc2fb714bcb7b8" +checksum = "40adba15f8099159d37d0a21e1cfb6602c2e49b6c05f6f8a57a47d0fb21611af" dependencies = [ - "log", - "markup5ever", + "bstr", + "gix-error", + "gix-glob", + "gix-hash", + "gix-revision", + "gix-validate", + "smallvec 1.15.1 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 2.0.20", ] [[package]] -name = "htmlize" -version = "1.0.6" +name = "gix-revision" +version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d347c0de239be20ba0982e4822de3124404281e119ae3e11f5d7425a414e1935" +checksum = "a75ef94c9d76de0765e429ae22a01c512c0d50459269195a90ea11099a5fc752" dependencies = [ - "memchr 2.7.6 (registry+https://github.com/rust-lang/crates.io-index)", - "pastey", - "phf 0.11.3", - "phf_codegen 0.11.3", - "serde_json", + "bitflags 2.13.1", + "bstr", + "gix-commitgraph", + "gix-date", + "gix-error", + "gix-hash", + "gix-hashtable", + "gix-object", + "gix-revwalk", + "gix-trace", ] [[package]] -name = "http" -version = "1.5.0" +name = "gix-revwalk" +version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "918d3568bebf352712bc2ef3d46a8bcf1a75b373be6539de198e9105cbbf9ce0" +checksum = "07efcad1d064abdac3e79dfc6e23e05accb579559d015e944c9dcf64be95eb49" dependencies = [ - "bytes", - "itoa", + "gix-commitgraph", + "gix-date", + "gix-error", + "gix-hash", + "gix-hashtable", + "gix-object", + "smallvec 1.15.1 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 2.0.20", ] [[package]] -name = "http-body" -version = "1.0.1" +name = "gix-sec" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +checksum = "283f4a746c9bde8550be63e6f961ff4651f412ca12666e8f5615f39464960ab9" dependencies = [ - "bytes", - "http", + "bitflags 2.13.1", + "gix-path", + "libc", + "windows-sys 0.61.1", ] [[package]] -name = "http-body-util" -version = "0.1.3" +name = "gix-shallow" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +checksum = "189386b5da5285216cc0ede89eff5a943d5261fc794241ee6ec5360b77df15ad" dependencies = [ - "bytes", - "futures-core", - "http", - "http-body", - "pin-project-lite", + "bstr", + "gix-hash", + "gix-lock", + "thiserror 2.0.20", ] [[package]] -name = "httparse" -version = "1.10.1" +name = "gix-submodule" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" +checksum = "ac5d38afa855046b7b9e2b85f8cdf7fbf2e449ed061dc81fa7a757abaa38bfac" +dependencies = [ + "bstr", + "gix-config", + "gix-path", + "gix-pathspec", + "gix-refspec", + "gix-url", + "thiserror 2.0.20", +] [[package]] -name = "httpdate" -version = "1.0.3" +name = "gix-tempfile" +version = "21.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +checksum = "d22227f6b203f511ff451c33c89899e87e4f571fc596b06f68e6e613a6508528" +dependencies = [ + "dashmap", + "gix-fs", + "libc", + "parking_lot", + "tempfile", +] [[package]] -name = "hybrid-array" -version = "0.4.15" +name = "gix-trace" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27f864f10dfb56725ce5ce5472bc52252c8f93a4ab86327122cebf62c5f59a17" +checksum = "be3eb81d9dc914335923e50d52829c551feefd6a72d176c4130c546b67a60814" + +[[package]] +name = "gix-transport" +version = "0.54.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9561a98f4f1cada03b565121c475c95d060998082bdb1277044fa6e11fe2aa17" dependencies = [ - "typenum", + "bstr", + "gix-command", + "gix-features", + "gix-packetline", + "gix-quote", + "gix-sec", + "gix-url", + "thiserror 2.0.20", ] [[package]] -name = "hyper" -version = "1.7.0" +name = "gix-traverse" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb3aa54a13a0dfe7fbe3a59e0c76093041720fdc77b110cc0fc260fafb4dc51e" +checksum = "bcdd399f8527f643f8d4fd8de6ec3b6e2c3c826b758b68e90f28275af2e7b33a" dependencies = [ - "atomic-waker", - "bytes", - "futures-channel", - "futures-core", - "h2", - "http", - "http-body", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "pin-utils", + "bitflags 2.13.1", + "gix-commitgraph", + "gix-date", + "gix-hash", + "gix-hashtable", + "gix-object", + "gix-revwalk", "smallvec 1.15.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio", - "want", + "thiserror 2.0.20", ] [[package]] -name = "hyper-rustls" -version = "0.27.7" +name = "gix-url" +version = "0.35.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" +checksum = "1a61ead12e33fa52ae92b207ee27554f646a8e7a3dad8b78da1582ec91eda0a6" dependencies = [ - "http", - "hyper", - "hyper-util", - "rustls", - "rustls-native-certs", - "rustls-pki-types", - "tokio", - "tokio-rustls", - "tower-service", + "bstr", + "gix-path", + "percent-encoding", + "thiserror 2.0.20", ] [[package]] -name = "hyper-tls" -version = "0.6.0" +name = "gix-utils" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" +checksum = "0da1c46491b49458a446cc76f0085860f8164c2290742e0aa8c653ce67240a97" dependencies = [ - "bytes", - "http-body-util", - "hyper", - "hyper-util", - "native-tls", - "tokio", - "tokio-native-tls", - "tower-service", + "fastrand", + "getrandom 0.4.3", + "unicode-normalization", ] [[package]] -name = "hyper-util" -version = "0.1.17" +name = "gix-validate" +version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c6995591a8f1380fcb4ba966a252a4b29188d51d2b89e3a252f5305be65aea8" +checksum = "4dae8780f63ed8a803b8bdabbd7aa5f5c5d74592c8b50eed875c1bb4f6545a6a" dependencies = [ - "base64 0.22.1", - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "http", - "http-body", - "hyper", - "ipnet", - "libc", - "percent-encoding", - "pin-project-lite", - "socket2", - "system-configuration", - "tokio", - "tower-service", - "tracing", - "windows-registry", + "bstr", ] [[package]] -name = "iana-time-zone" -version = "0.1.64" +name = "gix-worktree" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" +checksum = "93381c5cd37fa208e3f454433425985ea02725369fb33a79ff4ecf7c279f2f98" dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "log", - "wasm-bindgen", - "windows-core 0.62.2 (registry+https://github.com/rust-lang/crates.io-index)", + "bstr", + "gix-attributes", + "gix-fs", + "gix-glob", + "gix-hash", + "gix-ignore", + "gix-index", + "gix-object", + "gix-path", + "gix-validate", ] [[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" +name = "glifo" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +checksum = "ed4a1bb24121291d27230c1b1b44e07d6a9b28cefdb32fe1581dfb84e14f940a" dependencies = [ - "cc", + "bytemuck 1.25.2", + "foldhash 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hashbrown 0.17.1", + "log", + "peniko", + "skrifa", + "smallvec 1.15.1 (registry+https://github.com/rust-lang/crates.io-index)", + "vello_common", ] [[package]] -name = "icu_collections" -version = "2.3.0" +name = "glob" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa68d21081c4a05d5a901a1c62add574c77048b6a1c67be3b50ce0b60d4ca513" -dependencies = [ - "displaydoc", - "potential_utf", - "utf8_iter", - "yoke", - "zerofrom", - "zerovec", -] +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" [[package]] -name = "icu_locale_core" -version = "2.3.0" +name = "globset" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d56e28588da92eee5c3201a6eff33fabdd49b62269c8938d4ff050ce4d900deb" +checksum = "07c34a9410465b45bd9787443bc7370f37735bad04b0f0cd57ff1a3186c98988" dependencies = [ - "displaydoc", - "litemap", - "serde", - "tinystr", - "writeable", - "zerovec", + "aho-corasick", + "bstr", + "log", + "regex-automata", + "regex-syntax", ] [[package]] -name = "icu_locale_fallback" -version = "2.3.0" +name = "gloo-timers" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "251af8e57c9400e3eb58242fe5b8b1152b2a64fdf4cf632f923c38ccee6f2fa9" +checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" dependencies = [ - "icu_locale_core", - "icu_locale_fallback_data", - "icu_provider", - "potential_utf", - "tinystr", - "zerovec", + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", ] [[package]] -name = "icu_locale_fallback_data" -version = "2.3.0" +name = "gloo-timers" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "decf2a22ec8fa68f1a0c1129a3f8583f8f8bc24e8b9ccbe98ead99f62a4dc3a8" +checksum = "482ce8a491a501da4cd806bd190275363d674f2845005c6ddbd5d3e1dd54495d" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] [[package]] -name = "icu_normalizer" -version = "2.3.0" +name = "gloo-utils" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12f9cf5f235641ed274641dd81c3f28d870e276763d0797aeeab72317b1c646f" +checksum = "4202275d95a142fa209a1e35e91c250a710c5600731372cd3464a39ed01573d6" dependencies = [ - "icu_collections", - "icu_normalizer_data", - "icu_properties", - "icu_provider", - "smallvec 1.15.1 (registry+https://github.com/rust-lang/crates.io-index)", - "zerovec", + "js-sys", + "serde", + "serde_json", + "wasm-bindgen", + "web-sys", ] [[package]] -name = "icu_normalizer_data" -version = "2.3.0" +name = "goblin" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1563da1ed3e0b3bf3d74c9b85917ac9c56464d2f57242270c09c9e752f8021a0" +checksum = "17582616a7718cca54cec18e534a76c7c4aec11a8b9a85695712f262fd15a4c8" +dependencies = [ + "log", + "plain", + "scroll", +] [[package]] -name = "icu_properties" -version = "2.3.0" +name = "group" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e7ca276ad3145661a65914e6daf131ca5120cd3dcee8f8f3214b8875184a148" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ - "displaydoc", - "icu_collections", - "icu_locale_core", - "icu_properties_data", - "icu_provider", - "zerotrie", - "zerovec", + "ff", + "rand_core 0.6.4", + "subtle", ] [[package]] -name = "icu_properties_data" -version = "2.3.0" +name = "growable-bloom-filter" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e590f038c1464a96894fd6d10127e90a8be4509f56ff7ecef851b15cee0b7caa" - -[[package]] -name = "icu_provider" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d27bbb9d3abbefac45d55f647c9de1d44aafcd1186eb91879afef17c396c3e73" +checksum = "d174ccb4ba660d431329e7f0797870d0a4281e36353ec4b4a3c5eab6c2cfb6f1" dependencies = [ - "displaydoc", - "icu_locale_core", "serde", - "stable_deref_trait", - "writeable", - "yoke", - "zerofrom", - "zerotrie", - "zerovec", + "serde_bytes", + "serde_derive", + "xxhash-rust", ] [[package]] -name = "icu_segmenter" -version = "2.3.0" +name = "guillotiere" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82d07aafccd67af15d02512a6adf5896fbc5ed00f2e99b471d2efa14016db3db" +checksum = "6b17e70c989c36bad147b27a58d148c0741c51448aa5653436547323e524d0ab" dependencies = [ - "core_maths", - "icu_collections", - "icu_locale_fallback", - "icu_provider", - "icu_segmenter_data", - "potential_utf", - "smallvec 1.15.1 (registry+https://github.com/rust-lang/crates.io-index)", - "utf8_iter", - "zerovec", + "euclid 0.22.14", ] [[package]] -name = "icu_segmenter_data" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae293c039020f9ec10710af98d29ce6aa2051486638b49c9a6409f3b4a9e98ad" - -[[package]] -name = "ident_case" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" - -[[package]] -name = "idna" -version = "1.1.0" +name = "h2" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386" dependencies = [ - "idna_adapter", - "smallvec 1.15.1 (registry+https://github.com/rust-lang/crates.io-index)", - "utf8_iter", + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http", + "indexmap 2.14.2", + "slab", + "tokio", + "tokio-util", + "tracing", ] [[package]] -name = "idna_adapter" -version = "1.2.1" +name = "half" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" dependencies = [ - "icu_normalizer", - "icu_properties", + "cfg-if 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "crunchy 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "zerocopy 0.8.27", ] [[package]] -name = "image" -version = "0.25.10" +name = "harfrust" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85ab80394333c02fe689eaf900ab500fbd0c2213da414687ebf995a65d5a6104" +checksum = "c03d949a14aa089bbb282f7dd76a498a7f684428e4257202efc119ec010376f9" dependencies = [ + "bitflags 2.13.1", "bytemuck 1.25.2", - "byteorder-lite", - "moxcms", - "num-traits 0.2.19", - "png 0.18.1", - "tiff", - "zune-core", - "zune-jpeg", + "read-fonts", + "smallvec 1.15.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "image-webp" -version = "0.2.4" +name = "hash32" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "525e9ff3e1a4be2fbea1fdf0e98686a6d98b4d8f937e1bf7402245af1909e8c3" +checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" dependencies = [ - "byteorder-lite", - "quick-error", + "byteorder 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "imagesize" -version = "0.14.0" +name = "hashbrown" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09e54e57b4c48b40f7aec75635392b12b3421fa26fe8b4332e63138ed278459c" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] -name = "imbl" -version = "7.0.1" +name = "hashbrown" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43ea8d4c37ee560727e824d62804183624d371e632019b0e9e3532bce64a33e5" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ - "archery", - "bitmaps", + "allocator-api2", "equivalent 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "imbl-sized-chunks", - "rand_core 0.9.3", - "rand_xoshiro", - "serde_core", - "version_check", - "wide", + "foldhash 0.1.5", ] [[package]] -name = "imbl-sized-chunks" -version = "0.1.3" +name = "hashbrown" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f4241005618a62f8d57b2febd02510fb96e0137304728543dfc5fd6f052c22d" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" dependencies = [ - "bitmaps", + "allocator-api2", + "equivalent 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "foldhash 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "impartial-ord" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ab604ee7085efba6efc65e4ebca0e9533e3aff6cb501d7d77b211e3a781c6d5" +name = "hashbrown" +version = "0.16.1" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", + "foldhash 0.2.0 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", ] [[package]] -name = "indexmap" -version = "1.9.3" +name = "hashbrown" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" dependencies = [ - "autocfg", - "hashbrown 0.12.3", - "serde", + "foldhash 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "indexmap" -version = "2.13.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +name = "hashlink" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" dependencies = [ - "equivalent 1.0.2 (git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4)", - "hashbrown 0.16.1 (git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4)", + "hashbrown 0.15.5", ] [[package]] -name = "indexmap" -version = "2.14.2" +name = "hashlink" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc4e190f5d26ca7051642629da2c52fc03bde85a03197c99408dcd291734c855" +checksum = "a596f1b20ed2cc5ecac41a164aaebc7258057060f06c0cf7a2ba3991ee7990fb" dependencies = [ - "equivalent 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "hashbrown 0.17.1", - "serde", - "serde_core", ] [[package]] -name = "inout" -version = "0.1.4" +name = "heapless" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" dependencies = [ - "block-padding 0.3.3", - "generic-array", + "hash32", + "stable_deref_trait", ] [[package]] -name = "inout" -version = "0.2.2" +name = "heck" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4250ce6452e92010fdf7268ccc5d14faa80bb12fc741938534c58f16804e03c7" -dependencies = [ - "block-padding 0.4.2", - "hybrid-array", -] +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] -name = "ipnet" -version = "2.11.0" +name = "hermit-abi" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" [[package]] -name = "iri-string" -version = "0.7.8" +name = "hex" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" -dependencies = [ - "memchr 2.7.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde", -] +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] -name = "is_terminal_polyfill" -version = "1.70.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" +name = "hexf-parse" +version = "0.2.1" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] -name = "itertools" -version = "0.13.0" +name = "hilog-sys" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" -dependencies = [ - "either", -] +checksum = "f715f263b6e73aa2322b59057134b4daf56a765cbebc2f6b35e640ffded3361b" [[package]] -name = "itertools" -version = "0.14.0" +name = "hkdf" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" dependencies = [ - "either", + "hmac 0.12.1", ] [[package]] -name = "itertools" -version = "0.15.0" +name = "hkdf" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b4baf93f58d4425749ca49a51c50ebab072c5df6994d08fed93541c331481dc" +checksum = "4aaa26c720c68b866f2c96ef5c1264b3e6f473fe5d4ce61cd44bbe913e553018" dependencies = [ - "either", + "hmac 0.13.0", ] [[package]] -name = "itoa" -version = "1.0.15" +name = "hmac" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.7", +] [[package]] -name = "jetscii" -version = "0.5.3" +name = "hmac" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47f142fe24a9c9944451e8349de0a56af5f3e7226dc46f3ed4d4ecc0b85af75e" +checksum = "6303bc9732ae41b04cb554b844a762b4115a61bfaa81e3e83050991eeb56863f" +dependencies = [ + "digest 0.11.3", +] [[package]] -name = "jni" -version = "0.21.1" +name = "hnsw_rs" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" +checksum = "43a5258f079b97bf2e8311ff9579e903c899dcbac0d9a138d62e9a066778bd07" dependencies = [ - "cesu8", + "anndists", + "anyhow", + "bincode", "cfg-if 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "combine", - "jni-sys", + "cpu-time", + "env_logger", + "hashbrown 0.15.5", + "indexmap 2.14.2", + "lazy_static", "log", - "thiserror 1.0.69", - "walkdir", - "windows-sys 0.45.0", + "mmap-rs", + "num-traits 0.2.19", + "num_cpus", + "parking_lot", + "rand 0.9.2", + "rayon", + "serde", ] [[package]] -name = "jni-sys" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" - -[[package]] -name = "jobserver" -version = "0.1.34" +name = "home" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" dependencies = [ - "getrandom 0.3.3", - "libc", + "windows-sys 0.61.1", ] [[package]] -name = "js-sys" -version = "0.3.105" +name = "hound" +version = "3.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce57d20d1ea864ce2ac172ab472d409214f4fd359f0b2a2775abdf522e2af99e" -dependencies = [ - "cfg-if 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-util", - "wasm-bindgen", -] +checksum = "62adaabb884c94955b19907d60019f4e145d091c75345379e70d1ee696f7854f" [[package]] -name = "js_int" -version = "0.2.2" +name = "hpke" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d937f95470b270ce8b8950207715d71aa8e153c0d44c6684d59397ed4949160a" +checksum = "4917627a14198c3603282c5158b815ad5534795451d3c074b53cf3cee0960b11" dependencies = [ - "serde", + "aead 0.5.2", + "aes-gcm", + "chacha20poly1305 0.10.1", + "digest 0.10.7", + "generic-array", + "hkdf 0.12.4", + "hmac 0.12.1", + "p256", + "rand_core 0.6.4", + "sha2 0.10.9", + "subtle", + "x25519-dalek 2.0.1", + "zeroize", ] [[package]] -name = "js_option" -version = "0.2.0" +name = "hpke" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7dd3e281add16813cf673bf74a32249b0aa0d1c8117519a17b3ada5e8552b3c" +checksum = "a5324110b02044183df000f0bd7d2d7e61f1000631508627e77f63983b6fdffb" dependencies = [ - "serde_core", + "aead 0.6.1", + "chacha20poly1305 0.11.0", + "getrandom 0.4.3", + "hkdf 0.13.0", + "hybrid-array", + "rand_core 0.10.1", + "sha2 0.11.0", + "subtle", + "x25519-dalek 3.0.0", + "zeroize", ] [[package]] -name = "json5" -version = "1.3.1" +name = "htmd" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "733a844dbd6fef128e98cb4487b887cb55454d92cd9994b1bafe004fabbe670c" +checksum = "a5a1c7113c831fec68cbd79cd8bf281a84e5b6943f51473dc266b0b88a6a017e" dependencies = [ - "serde", - "ucd-trie", + "html5ever 0.38.0", + "markup5ever_rcdom 0.38.0+unofficial", + "phf 0.13.1", ] [[package]] -name = "k256" -version = "0.13.4" +name = "html-escape" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" -dependencies = [ - "cfg-if 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "ecdsa", - "elliptic-curve", - "sha2 0.10.9", -] +checksum = "c9356095b4b41197bba32173600e1582792cda618f65d12f68e2e77d273413c5" [[package]] -name = "keyboard-types" -version = "0.7.0" +name = "html5ever" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b750dcadc39a09dbadd74e118f6dd6598df77fa01df0cfcdc52c28dece74528a" +checksum = "55d958c2f74b664487a2035fe1dadb032c48718a03b63f3ab0b8537db8549ed4" dependencies = [ - "bitflags 2.13.1", - "serde", - "unicode-segmentation 1.13.3", + "log", + "markup5ever 0.35.0", + "match_token", ] [[package]] -name = "konst" -version = "0.4.3" +name = "html5ever" +version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f660d5f887e3562f9ab6f4a14988795b694099d66b4f5dedc02d197ba9becb1d" +checksum = "1054432bae2f14e0061e33d23402fbaa67a921d319d56adc6bcf887ddad1cbc2" dependencies = [ - "const_panic", - "typewit", + "log", + "markup5ever 0.38.0", ] [[package]] -name = "kurbo" -version = "0.13.1" +name = "html5ever" +version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b60dfc32f652b926df6192e55525b16d186c69d47876c3ead4da5cc9f8450e2" +checksum = "46a1761807faccc9a19e86944bbf40610014066306f96edcdedc2fb714bcb7b8" dependencies = [ - "arrayvec 0.7.8", - "euclid", - "polycool", - "smallvec 1.15.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log", + "markup5ever 0.39.0", ] [[package]] -name = "language-tags" -version = "0.3.2" +name = "htmlize" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4345964bb142484797b161f473a503a434de77149dd8c7427788c6e13379388" +checksum = "d347c0de239be20ba0982e4822de3124404281e119ae3e11f5d7425a414e1935" +dependencies = [ + "memchr 2.7.6 (registry+https://github.com/rust-lang/crates.io-index)", + "pastey 0.1.1", + "phf 0.11.3", + "phf_codegen 0.11.3", + "serde_json", +] [[package]] -name = "lazy_static" +name = "http" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +checksum = "918d3568bebf352712bc2ef3d46a8bcf1a75b373be6539de198e9105cbbf9ce0" dependencies = [ - "spin", + "bytes", + "itoa", ] [[package]] -name = "libc" -version = "0.2.186" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" - -[[package]] -name = "libloading" -version = "0.8.8" +name = "http-body" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ - "cfg-if 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "windows-targets 0.53.4", + "bytes", + "http", ] [[package]] -name = "libloading" -version = "0.8.9" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +name = "http-body-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ - "cfg-if 1.0.4 (git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4)", - "windows-link 0.2.1 (git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4)", + "bytes", + "futures-core", + "http", + "http-body", + "pin-project-lite", ] [[package]] -name = "libm" -version = "0.2.15" +name = "httparse" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" [[package]] -name = "libredox" -version = "0.1.10" +name = "httpdate" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" -dependencies = [ - "bitflags 2.13.1", - "libc", - "redox_syscall", -] +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] -name = "libsqlite3-sys" -version = "0.38.2" +name = "hybrid-array" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1d20bef17f513b9b3004532233187769cd072d790971f4e4da0e346eb6401e8" +checksum = "27f864f10dfb56725ce5ce5472bc52252c8f93a4ab86327122cebf62c5f59a17" dependencies = [ - "cc", - "pkg-config 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)", - "vcpkg", + "typenum", ] [[package]] -name = "linebender_resource_handle" -version = "0.1.1" +name = "hyper" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4a5ff6bcca6c4867b1c4fd4ef63e4db7436ef363e0ad7531d1558856bae64f4" +checksum = "eb3aa54a13a0dfe7fbe3a59e0c76093041720fdc77b110cc0fc260fafb4dc51e" +dependencies = [ + "atomic-waker", + "bytes", + "futures-channel", + "futures-core", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "pin-utils", + "smallvec 1.15.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio", + "want", +] [[package]] -name = "linkify" -version = "0.10.0" +name = "hyper-rustls" +version = "0.27.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1dfa36d52c581e9ec783a7ce2a5e0143da6237be5811a0b3153fedfdbe9f780" +checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" dependencies = [ - "memchr 2.7.6 (registry+https://github.com/rust-lang/crates.io-index)", + "http", + "hyper", + "hyper-util", + "rustls", + "rustls-native-certs", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower-service", + "webpki-roots", ] [[package]] -name = "linux-raw-sys" -version = "0.12.1" +name = "hyper-tls" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" +dependencies = [ + "bytes", + "http-body-util", + "hyper", + "hyper-util", + "native-tls", + "tokio", + "tokio-native-tls", + "tower-service", +] [[package]] -name = "litemap" -version = "0.8.0" +name = "hyper-util" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" - -[[package]] -name = "lock_api" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" +checksum = "3c6995591a8f1380fcb4ba966a252a4b29188d51d2b89e3a252f5305be65aea8" dependencies = [ - "autocfg", - "scopeguard", + "base64 0.22.1", + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "http", + "http-body", + "hyper", + "ipnet", + "libc", + "percent-encoding", + "pin-project-lite", + "socket2", + "system-configuration", + "tokio", + "tower-service", + "tracing", + "windows-registry 0.5.3", ] [[package]] -name = "log" -version = "0.4.34" +name = "iana-time-zone" +version = "0.1.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6" +checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core 0.56.0", +] [[package]] -name = "loom" -version = "0.7.2" +name = "iana-time-zone-haiku" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "419e0dc8046cb947daa77eb95ae174acfbddb7673b4151f56d1eed8e93fbfaca" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" dependencies = [ - "cfg-if 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "generator", - "scoped-tls 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tracing", - "tracing-subscriber", + "cc", ] [[package]] -name = "lru" -version = "0.16.4" +name = "icu_collections" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f66e8d5d03f609abc3a39e6f08e4164ebf1447a732906d39eb9b99b7919ef39" +checksum = "fa68d21081c4a05d5a901a1c62add574c77048b6a1c67be3b50ce0b60d4ca513" dependencies = [ - "hashbrown 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)", + "displaydoc", + "potential_utf", + "utf8_iter", + "yoke", + "zerofrom", + "zerovec", ] [[package]] -name = "lru-slab" -version = "0.1.2" +name = "icu_locale_core" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" +checksum = "d56e28588da92eee5c3201a6eff33fabdd49b62269c8938d4ff050ce4d900deb" +dependencies = [ + "displaydoc", + "litemap", + "serde", + "tinystr", + "writeable", + "zerovec", +] [[package]] -name = "macroific" -version = "2.0.0" +name = "icu_locale_fallback" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89f276537b4b8f981bf1c13d79470980f71134b7bdcc5e6e911e910e556b0285" +checksum = "251af8e57c9400e3eb58242fe5b8b1152b2a64fdf4cf632f923c38ccee6f2fa9" dependencies = [ - "macroific_attr_parse", - "macroific_core", - "macroific_macro", + "icu_locale_core", + "icu_locale_fallback_data", + "icu_provider", + "potential_utf", + "tinystr", + "zerovec", ] [[package]] -name = "macroific_attr_parse" -version = "2.0.0" +name = "icu_locale_fallback_data" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad4023761b45fcd36abed8fb7ae6a80456b0a38102d55e89a57d9a594a236be9" -dependencies = [ - "proc-macro2", - "quote", - "sealed", - "syn 2.0.119", -] +checksum = "decf2a22ec8fa68f1a0c1129a3f8583f8f8bc24e8b9ccbe98ead99f62a4dc3a8" [[package]] -name = "macroific_core" -version = "2.0.0" +name = "icu_normalizer" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a7594d3c14916fa55bef7e9d18c5daa9ed410dd37504251e4b75bbdeec33e3" +checksum = "12f9cf5f235641ed274641dd81c3f28d870e276763d0797aeeab72317b1c646f" dependencies = [ - "proc-macro2", - "quote", - "sealed", - "syn 2.0.119", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec 1.15.1 (registry+https://github.com/rust-lang/crates.io-index)", + "zerovec", ] [[package]] -name = "macroific_macro" -version = "2.0.0" +name = "icu_normalizer_data" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4da6f2ed796261b0a74e2b52b42c693bb6dee1effba3a482c49592659f824b3b" -dependencies = [ - "macroific_attr_parse", - "macroific_core", - "proc-macro2", - "quote", - "syn 2.0.119", -] +checksum = "1563da1ed3e0b3bf3d74c9b85917ac9c56464d2f57242270c09c9e752f8021a0" [[package]] -name = "makepad-ai-services" -version = "0.1.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +name = "icu_properties" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e7ca276ad3145661a65914e6daf131ca5120cd3dcee8f8f3214b8875184a148" dependencies = [ - "makepad-micro-serde", - "makepad-platform", - "makepad-strict-json", + "displaydoc", + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", ] [[package]] -name = "makepad-android-state" -version = "0.1.0" +name = "icu_properties_data" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd004cda8be459fd76954218b76a1249a079fb9360bbca4e724cb7ddb2962857" -dependencies = [ - "makepad-jni-sys", -] +checksum = "e590f038c1464a96894fd6d10127e90a8be4509f56ff7ecef851b15cee0b7caa" [[package]] -name = "makepad-app-module" -version = "0.1.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +name = "icu_provider" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d27bbb9d3abbefac45d55f647c9de1d44aafcd1186eb91879afef17c396c3e73" dependencies = [ - "makepad-ai-services", - "makepad-strict-json", - "makepad-widgets", + "displaydoc", + "icu_locale_core", + "serde", + "stable_deref_trait", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", ] [[package]] -name = "makepad-apple-sys" -version = "1.0.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +name = "icu_segmenter" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82d07aafccd67af15d02512a6adf5896fbc5ed00f2e99b471d2efa14016db3db" dependencies = [ - "makepad-objc-sys", + "core_maths", + "icu_collections", + "icu_locale_fallback", + "icu_provider", + "icu_segmenter_data", + "potential_utf", + "smallvec 1.15.1 (registry+https://github.com/rust-lang/crates.io-index)", + "utf8_iter", + "zerovec", ] [[package]] -name = "makepad-byteorder-lite" -version = "0.1.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +name = "icu_segmenter_data" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae293c039020f9ec10710af98d29ce6aa2051486638b49c9a6409f3b4a9e98ad" [[package]] -name = "makepad-code-editor" -version = "2.0.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" -dependencies = [ - "makepad-widgets", -] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] -name = "makepad-derive-wasm-bridge" -version = "1.0.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" dependencies = [ - "makepad-micro-proc-macro", + "idna_adapter", + "smallvec 1.15.1 (registry+https://github.com/rust-lang/crates.io-index)", + "utf8_iter", ] [[package]] -name = "makepad-derive-widget" -version = "2.0.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" dependencies = [ - "makepad-live-id", - "makepad-micro-proc-macro", + "icu_normalizer", + "icu_properties", ] [[package]] -name = "makepad-draw" -version = "2.0.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +name = "ignore" +version = "0.4.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b69833ed729dc5aa7d19541d96d6cf8e9137194207a04916d658e43168402f" dependencies = [ - "ab_glyph_rasterizer", - "fxhash", - "makepad-gif", - "makepad-live-id", - "makepad-math", - "makepad-platform", - "makepad-svg", - "makepad-webp", - "makepad-zune-bmp", - "makepad-zune-jpeg", - "makepad-zune-png", - "makepad-zune-qoi", - "rustybuzz 0.18.0", - "sdfer", - "serde", - "ttf-parser 0.24.1", - "unicode-bidi 0.3.18 (git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4)", - "unicode-linebreak", - "unicode-segmentation 1.12.0", + "crossbeam-deque", + "globset", + "log", + "memchr 2.7.6 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-automata", + "same-file", + "walkdir", + "winapi-util", ] [[package]] -name = "makepad-error-log" -version = "1.0.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +name = "image" +version = "0.25.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85ab80394333c02fe689eaf900ab500fbd0c2213da414687ebf995a65d5a6104" dependencies = [ - "makepad-micro-serde", + "bytemuck 1.25.2", + "byteorder-lite", + "moxcms", + "num-traits 0.2.19", + "png 0.18.1", + "tiff", + "zune-core", + "zune-jpeg", ] [[package]] -name = "makepad-fast-inflate" -version = "0.1.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" - -[[package]] -name = "makepad-filesystem-watcher" -version = "0.1.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +name = "image-webp" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525e9ff3e1a4be2fbea1fdf0e98686a6d98b4d8f937e1bf7402245af1909e8c3" dependencies = [ - "makepad-git", + "byteorder-lite", + "quick-error", ] [[package]] -name = "makepad-futures" -version = "1.0.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +name = "imagesize" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09e54e57b4c48b40f7aec75635392b12b3421fa26fe8b4332e63138ed278459c" [[package]] -name = "makepad-futures-legacy" -version = "1.0.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +name = "imara-diff" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17d34b7d42178945f775e84bc4c36dde7c1c6cdfea656d3354d009056f2bb3d2" +dependencies = [ + "hashbrown 0.15.5", +] [[package]] -name = "makepad-gif" -version = "0.1.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +name = "imbl" +version = "7.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43ea8d4c37ee560727e824d62804183624d371e632019b0e9e3532bce64a33e5" dependencies = [ - "weezl 0.1.12 (git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4)", + "archery", + "bitmaps", + "equivalent 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "imbl-sized-chunks", + "rand_core 0.9.3", + "rand_xoshiro", + "serde_core", + "version_check", + "wide", ] [[package]] -name = "makepad-git" -version = "0.1.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +name = "imbl-sized-chunks" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f4241005618a62f8d57b2febd02510fb96e0137304728543dfc5fd6f052c22d" dependencies = [ - "makepad-fast-inflate", + "bitmaps", ] [[package]] -name = "makepad-half" -version = "2.7.1" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +name = "impartial-ord" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ab604ee7085efba6efc65e4ebca0e9533e3aff6cb501d7d77b211e3a781c6d5" dependencies = [ - "cfg-if 1.0.4 (git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4)", - "crunchy 0.2.4 (git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4)", - "num-traits 0.2.20", - "zerocopy 0.8.39", + "proc-macro2", + "quote", + "syn 2.0.119", ] [[package]] -name = "makepad-html" -version = "0.1.0" -source = "git+https://github.com/OctoSense-org/makepad-html?rev=b16565ae1e56dd7c3a87f00455ae327df599ca3b#b16565ae1e56dd7c3a87f00455ae327df599ca3b" +name = "indenter" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "964de6e86d545b246d84badc0fef527924ace5134f30641c203ef52ba83f58d5" + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ - "anyrender", - "anyrender_vello_cpu", - "blitz-dom", - "blitz-html", - "blitz-paint", - "blitz-traits", - "html5ever", - "image", - "makepad-widgets", - "peniko", - "thiserror 2.0.20", + "autocfg", + "hashbrown 0.12.3", + "serde", ] [[package]] -name = "makepad-html" -version = "1.0.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +name = "indexmap" +version = "2.13.0" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ - "makepad-live-id", + "equivalent 1.0.2 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", + "hashbrown 0.16.1 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", ] [[package]] -name = "makepad-jni-sys" -version = "0.4.0" +name = "indexmap" +version = "2.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9775cbec5fa0647500c3e5de7c850280a88335d1d2d770e5aa2332b801ba7064" +checksum = "cc4e190f5d26ca7051642629da2c52fc03bde85a03197c99408dcd291734c855" +dependencies = [ + "equivalent 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "hashbrown 0.17.1", + "serde", + "serde_core", +] [[package]] -name = "makepad-latex-math" -version = "0.1.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +name = "inout" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" dependencies = [ - "ttf-parser 0.24.1", + "block-padding 0.3.3", + "generic-array", ] [[package]] -name = "makepad-live-id" -version = "1.0.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +name = "inout" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4250ce6452e92010fdf7268ccc5d14faa80bb12fc741938534c58f16804e03c7" dependencies = [ - "makepad-live-id-macros", + "block-padding 0.4.2", + "hybrid-array", +] + +[[package]] +name = "ipnet" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" + +[[package]] +name = "iri-string" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" +dependencies = [ + "memchr 2.7.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde", ] [[package]] -name = "makepad-live-id-macros" -version = "1.0.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +name = "is-docker" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "928bae27f42bc99b60d9ac7334e3a21d10ad8f1835a4e12ec3ec0464765ed1b3" dependencies = [ - "makepad-micro-proc-macro", + "once_cell 1.21.4", ] [[package]] -name = "makepad-live-reload-core" -version = "0.1.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +name = "is-wsl" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "173609498df190136aa7dea1a91db051746d339e18476eed5ca40521f02d7aa5" dependencies = [ - "makepad-filesystem-watcher", + "is-docker", + "once_cell 1.21.4", ] [[package]] -name = "makepad-markdown" -version = "0.1.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" dependencies = [ - "blake3", - "comrak", - "emojis", - "html5ever", - "pulldown-cmark 0.13.0", - "unicode-segmentation 1.13.3", - "url", + "either", ] [[package]] -name = "makepad-markdown-widgets" -version = "0.1.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" dependencies = [ - "blake3", - "core-foundation 0.10.1", - "image", - "makepad-latex-math", - "makepad-markdown", - "makepad-widgets", - "mermaid-rs-renderer", - "resvg", - "roxmltree 0.21.1", - "syntect", - "tiny-skia", - "ttf-parser 0.24.1", - "unicode-segmentation 1.12.0", + "either", ] [[package]] -name = "makepad-math" -version = "1.0.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +name = "itertools" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b4baf93f58d4425749ca49a51c50ebab072c5df6994d08fed93541c331481dc" dependencies = [ - "makepad-micro-serde", + "either", ] [[package]] -name = "makepad-micro-proc-macro" -version = "1.0.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" [[package]] -name = "makepad-micro-serde" -version = "1.0.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +name = "jetscii" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47f142fe24a9c9944451e8349de0a56af5f3e7226dc46f3ed4d4ecc0b85af75e" + +[[package]] +name = "jiff" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ab1baf72f08796de0260609515130699b890ac25f30e610ad894bc5856cafdb" dependencies = [ - "makepad-live-id", - "makepad-micro-serde-derive", + "defmt", + "jiff-core", + "jiff-static", + "jiff-tzdb-platform", + "log", + "portable-atomic", + "portable-atomic-util", + "serde_core", + "windows-link 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "makepad-micro-serde-derive" -version = "1.0.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +name = "jiff-core" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e52fe76043ccecc9005d2305ebaadf7d7fc0cc89ca6baa10a94d6bc68c7128c" dependencies = [ - "makepad-micro-proc-macro", + "defmt", + "log", ] [[package]] -name = "makepad-network" -version = "1.0.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +name = "jiff-static" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "378268a1116ad67ae6228701118ac9f491d78fda38a40a1f1a9e1348de6f7212" dependencies = [ - "makepad-apple-sys", - "makepad-error-log", - "makepad-futures-legacy", - "makepad-live-id", - "makepad-micro-serde", - "makepad-script", - "windows 0.62.2 (git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4)", + "jiff-core", + "proc-macro2", + "quote", + "syn 2.0.119", ] [[package]] -name = "makepad-objc-sys" -version = "1.0.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +name = "jiff-tzdb" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "142bd39932ad231f10513df9ab62661fead8719872150b7ad02a2df79f4e141e" [[package]] -name = "makepad-platform" -version = "2.0.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +name = "jiff-tzdb-platform" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "875a5a69ac2bab1a891711cf5eccbec1ce0341ea805560dcd90b7a2e925132e8" dependencies = [ - "ash", - "bitflags 2.10.0", - "hilog-sys", - "makepad-android-state", - "makepad-apple-sys", - "makepad-futures", - "makepad-futures-legacy", - "makepad-jni-sys", - "makepad-live-reload-core", - "makepad-network", - "makepad-objc-sys", - "makepad-platform-video", - "makepad-script", - "makepad-script-std", - "makepad-shared-bytes", - "makepad-studio-protocol", - "makepad-tsdf", - "makepad-wasm-bridge", - "makepad-zune-png", - "naga", - "napi-derive-ohos", - "napi-ohos", - "ohos-sys", - "rqrr", - "smallvec 1.15.1 (git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4)", - "wayland-client", - "wayland-egl", - "wayland-protocols", - "windows 0.62.2 (git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4)", - "windows-core 0.62.2 (git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4)", - "windows-targets 0.52.6", -] - -[[package]] -name = "makepad-platform-video" -version = "1.0.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" -dependencies = [ - "makepad-apple-sys", - "makepad-objc-sys", - "windows 0.62.2 (git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4)", + "jiff-tzdb", ] [[package]] -name = "makepad-regex" -version = "0.1.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" - -[[package]] -name = "makepad-script" -version = "1.0.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +name = "jni" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" dependencies = [ - "makepad-error-log", - "makepad-html 1.0.0", - "makepad-live-id", - "makepad-math", - "makepad-regex", - "makepad-script-derive", - "makepad-stitch", - "smallvec 1.15.1 (git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4)", + "cesu8", + "cfg-if 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "combine", + "jni-sys 0.3.0", + "log", + "thiserror 1.0.69", + "walkdir", + "windows-sys 0.45.0", ] [[package]] -name = "makepad-script-derive" -version = "1.0.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +name = "jni" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5efd9a482cf3a427f00d6b35f14332adc7902ce91efb778580e180ff90fa3498" dependencies = [ - "makepad-micro-proc-macro", + "cfg-if 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "combine", + "jni-macros", + "jni-sys 0.4.1", + "log", + "simd_cesu8", + "thiserror 2.0.20", + "walkdir", + "windows-link 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "makepad-script-std" -version = "1.0.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +name = "jni-macros" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a00109accc170f0bdb141fed3e393c565b6f5e072365c3bd58f5b062591560a3" dependencies = [ - "makepad-network", - "makepad-script", + "proc-macro2", + "quote", + "rustc_version", + "simd_cesu8", + "syn 2.0.119", ] [[package]] -name = "makepad-shared-bytes" -version = "1.0.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] -name = "makepad-stitch" -version = "0.1.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +name = "jni-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2" +dependencies = [ + "jni-sys-macros", +] [[package]] -name = "makepad-strict-json" -version = "0.1.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +name = "jni-sys-macros" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" +dependencies = [ + "quote", + "syn 2.0.119", +] [[package]] -name = "makepad-studio-protocol" -version = "0.1.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +name = "jobserver" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" dependencies = [ - "bitflags 2.10.0", - "makepad-error-log", - "makepad-live-id", - "makepad-micro-serde", - "makepad-script", + "getrandom 0.3.3", + "libc", ] [[package]] -name = "makepad-svg" -version = "1.0.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +name = "js-sys" +version = "0.3.105" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce57d20d1ea864ce2ac172ab472d409214f4fd359f0b2a2775abdf522e2af99e" dependencies = [ - "makepad-html 1.0.0", - "makepad-live-id", + "cfg-if 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-util", + "wasm-bindgen", ] [[package]] -name = "makepad-tsdf" -version = "0.1.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +name = "js_int" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d937f95470b270ce8b8950207715d71aa8e153c0d44c6684d59397ed4949160a" dependencies = [ - "makepad-math", - "makepad-micro-serde", + "serde", ] [[package]] -name = "makepad-wasm-bridge" -version = "1.0.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +name = "js_option" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7dd3e281add16813cf673bf74a32249b0aa0d1c8117519a17b3ada5e8552b3c" dependencies = [ - "makepad-derive-wasm-bridge", - "makepad-live-id", + "serde_core", ] [[package]] -name = "makepad-webp" -version = "0.2.4" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +name = "json5" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "733a844dbd6fef128e98cb4487b887cb55454d92cd9994b1bafe004fabbe670c" dependencies = [ - "makepad-byteorder-lite", + "serde", + "ucd-trie", ] [[package]] -name = "makepad-widgets" -version = "2.0.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +name = "jsonwebtoken" +version = "9.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a87cc7a48537badeae96744432de36f4be2b4a34a05a5ef32e9dd8a1c169dde" dependencies = [ - "makepad-derive-widget", - "makepad-draw", - "makepad-html 1.0.0", - "makepad-latex-math", - "octoscript-node", - "pulldown-cmark 0.12.2", + "base64 0.22.1", + "js-sys", + "pem", + "ring", "serde", "serde_json", - "ttf-parser 0.24.1", - "unicode-segmentation 1.12.0", + "simple_asn1", ] [[package]] -name = "makepad-zune-bmp" -version = "0.5.2" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +name = "k256" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" dependencies = [ - "makepad-error-log", - "makepad-zune-core", + "cfg-if 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "ecdsa", + "elliptic-curve", + "sha2 0.10.9", ] [[package]] -name = "makepad-zune-core" -version = "0.5.1" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +name = "keyboard-types" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b750dcadc39a09dbadd74e118f6dd6598df77fa01df0cfcdc52c28dece74528a" dependencies = [ - "makepad-error-log", + "bitflags 2.13.1", + "serde", + "unicode-segmentation 1.13.3", ] [[package]] -name = "makepad-zune-inflate" -version = "0.2.54" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +name = "keyring" +version = "3.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eebcc3aff044e5944a8fbaf69eb277d11986064cba30c468730e8b9909fb551c" dependencies = [ - "simd-adler32 0.3.9", + "byteorder 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "linux-keyutils", + "log", + "security-framework 2.11.1", + "security-framework 3.5.0", + "windows-sys 0.60.2", + "zeroize", ] [[package]] -name = "makepad-zune-jpeg" -version = "0.5.15" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +name = "konst" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f660d5f887e3562f9ab6f4a14988795b694099d66b4f5dedc02d197ba9becb1d" dependencies = [ - "makepad-zune-core", + "const_panic", + "typewit", ] [[package]] -name = "makepad-zune-png" -version = "0.5.2" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +name = "kstring" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a09b82a7f771ed02dc0dd9b27130a0fa5499fa15ed3027116c1e5e4e591bd9e" dependencies = [ - "makepad-fast-inflate", - "makepad-zune-core", - "makepad-zune-inflate", + "static_assertions", ] [[package]] -name = "makepad-zune-qoi" -version = "0.5.2" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +name = "kurbo" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b60dfc32f652b926df6192e55525b16d186c69d47876c3ead4da5cc9f8450e2" dependencies = [ - "makepad-zune-core", + "arrayvec 0.7.8", + "euclid 0.22.14", + "polycool", + "smallvec 1.15.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "malloc_size_of_derive" -version = "0.1.3" +name = "landlock" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f44db74bde26fdf427af23f1d146c211aed857c59e3be750cf2617f6b0b05c94" +checksum = "4cca98e95f35b29d469dade6724c6f96cec9236640f745a0e99b0334ec320ab1" dependencies = [ - "proc-macro2", - "syn 2.0.119", - "synstructure 0.13.2", + "enumflags2", + "libc", + "thiserror 2.0.20", ] [[package]] -name = "maplit" -version = "1.0.2" +name = "language-tags" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" +checksum = "d4345964bb142484797b161f473a503a434de77149dd8c7427788c6e13379388" [[package]] -name = "markup5ever" -version = "0.39.0" +name = "lazy_static" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7122d987ec5f704ee56f6e5b41a7d93722e9aae27ae07cafa4036c4d3f9757de" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" dependencies = [ - "log", - "tendril", - "web_atoms", + "spin", ] [[package]] -name = "matchers" -version = "0.2.0" +name = "lddtree" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" +checksum = "547a362ad16dead8837d5b30402a81b05bb57c352044389f8748f4f2dbd51914" dependencies = [ - "regex-automata", + "fs-err", + "glob", + "goblin", ] [[package]] -name = "matchit" -version = "0.8.4" +name = "lettre" +version = "0.11.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" - -[[package]] -name = "matrix-pickle" -version = "0.2.3" +checksum = "f2c646bd5cc763b1087b15493e29a64be6147ba8f19342004fa52048ee596eae" +dependencies = [ + "async-trait", + "base64 0.23.1", + "email-encoding", + "email_address", + "fastrand", + "futures-io", + "futures-util", + "httpdate", + "idna", + "mime", + "nom 8.0.0", + "percent-encoding", + "quoted_printable", + "rustls", + "socket2", + "tokio", + "tokio-rustls", + "url", + "webpki-roots", +] + +[[package]] +name = "libc" +version = "0.2.186" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" + +[[package]] +name = "libloading" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" +dependencies = [ + "cfg-if 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "windows-targets 0.53.4", +] + +[[package]] +name = "libloading" +version = "0.8.9" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +dependencies = [ + "cfg-if 1.0.4 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", + "windows-link 0.2.1 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", +] + +[[package]] +name = "libm" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" + +[[package]] +name = "libredox" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" +dependencies = [ + "bitflags 2.13.1", + "libc", + "redox_syscall", +] + +[[package]] +name = "libsqlite3-sys" +version = "0.38.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1d20bef17f513b9b3004532233187769cd072d790971f4e4da0e346eb6401e8" +dependencies = [ + "cc", + "pkg-config 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)", + "vcpkg", +] + +[[package]] +name = "libyml" +version = "0.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3302702afa434ffa30847a83305f0a69d6abd74293b6554c18ec85c7ef30c980" +dependencies = [ + "anyhow", + "version_check", +] + +[[package]] +name = "linebender_resource_handle" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4a5ff6bcca6c4867b1c4fd4ef63e4db7436ef363e0ad7531d1558856bae64f4" + +[[package]] +name = "linkify" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1dfa36d52c581e9ec783a7ce2a5e0143da6237be5811a0b3153fedfdbe9f780" +dependencies = [ + "memchr 2.7.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "linux-keyutils" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83270a18e9f90d0707c41e9f35efada77b64c0e6f3f1810e71c8368a864d5590" +dependencies = [ + "bitflags 2.13.1", + "libc", +] + +[[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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" + +[[package]] +name = "lock_api" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6" + +[[package]] +name = "loom" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "419e0dc8046cb947daa77eb95ae174acfbddb7673b4151f56d1eed8e93fbfaca" +dependencies = [ + "cfg-if 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "generator", + "scoped-tls 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "lopdf" +version = "0.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59fa2559e99ba0f26a12458aabc754432c805bbb8cba516c427825a997af1fb7" +dependencies = [ + "aes 0.8.4", + "bitflags 2.13.1", + "cbc 0.1.2", + "ecb", + "encoding_rs", + "flate2", + "indexmap 2.14.2", + "itoa", + "log", + "md-5", + "nom 8.0.0", + "nom_locate", + "rand 0.9.2", + "rangemap", + "sha2 0.10.9", + "stringprep", + "thiserror 2.0.20", + "weezl 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "lru" +version = "0.16.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f66e8d5d03f609abc3a39e6f08e4164ebf1447a732906d39eb9b99b7919ef39" +dependencies = [ + "hashbrown 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + +[[package]] +name = "lzma-rs" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "297e814c836ae64db86b36cf2a557ba54368d03f6afcd7d947c266692f71115e" +dependencies = [ + "byteorder 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crc", +] + +[[package]] +name = "lzma-sys" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fda04ab3764e6cde78b9974eec4f779acaba7c4e84b36eca3cf77c581b85d27" +dependencies = [ + "cc", + "libc", + "pkg-config 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "mac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" + +[[package]] +name = "mach2" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d640282b302c0bb0a2a8e0233ead9035e3bed871f0b7e81fe4a1ec829765db44" +dependencies = [ + "libc", +] + +[[package]] +name = "macroific" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89f276537b4b8f981bf1c13d79470980f71134b7bdcc5e6e911e910e556b0285" +dependencies = [ + "macroific_attr_parse", + "macroific_core", + "macroific_macro", +] + +[[package]] +name = "macroific_attr_parse" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad4023761b45fcd36abed8fb7ae6a80456b0a38102d55e89a57d9a594a236be9" +dependencies = [ + "proc-macro2", + "quote", + "sealed", + "syn 2.0.119", +] + +[[package]] +name = "macroific_core" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a7594d3c14916fa55bef7e9d18c5daa9ed410dd37504251e4b75bbdeec33e3" +dependencies = [ + "proc-macro2", + "quote", + "sealed", + "syn 2.0.119", +] + +[[package]] +name = "macroific_macro" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4da6f2ed796261b0a74e2b52b42c693bb6dee1effba3a482c49592659f824b3b" +dependencies = [ + "macroific_attr_parse", + "macroific_core", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "makepad-ai-services" +version = "0.1.0" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +dependencies = [ + "makepad-micro-serde", + "makepad-platform", + "makepad-strict-json", +] + +[[package]] +name = "makepad-android-state" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd004cda8be459fd76954218b76a1249a079fb9360bbca4e724cb7ddb2962857" +dependencies = [ + "makepad-jni-sys", +] + +[[package]] +name = "makepad-app-module" +version = "0.1.0" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +dependencies = [ + "makepad-ai-services", + "makepad-strict-json", + "makepad-widgets", +] + +[[package]] +name = "makepad-apple-sys" +version = "1.0.0" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +dependencies = [ + "makepad-objc-sys", +] + +[[package]] +name = "makepad-byteorder-lite" +version = "0.1.0" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" + +[[package]] +name = "makepad-code-editor" +version = "2.0.0" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +dependencies = [ + "makepad-widgets", +] + +[[package]] +name = "makepad-derive-wasm-bridge" +version = "1.0.0" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +dependencies = [ + "makepad-micro-proc-macro", +] + +[[package]] +name = "makepad-derive-widget" +version = "2.0.0" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +dependencies = [ + "makepad-live-id", + "makepad-micro-proc-macro", +] + +[[package]] +name = "makepad-draw" +version = "2.0.0" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +dependencies = [ + "ab_glyph_rasterizer", + "fxhash", + "makepad-gif", + "makepad-live-id", + "makepad-math", + "makepad-platform", + "makepad-svg", + "makepad-webp", + "makepad-zune-bmp", + "makepad-zune-jpeg", + "makepad-zune-png", + "makepad-zune-qoi", + "rustybuzz 0.18.0", + "sdfer", + "serde", + "ttf-parser 0.24.1", + "unicode-bidi 0.3.18 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", + "unicode-linebreak", + "unicode-segmentation 1.12.0", +] + +[[package]] +name = "makepad-error-log" +version = "1.0.0" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +dependencies = [ + "makepad-micro-serde", +] + +[[package]] +name = "makepad-fast-inflate" +version = "0.1.0" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" + +[[package]] +name = "makepad-filesystem-watcher" +version = "0.1.0" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +dependencies = [ + "makepad-git", +] + +[[package]] +name = "makepad-futures" +version = "1.0.0" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" + +[[package]] +name = "makepad-futures-legacy" +version = "1.0.0" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" + +[[package]] +name = "makepad-gif" +version = "0.1.0" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +dependencies = [ + "weezl 0.1.12 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", +] + +[[package]] +name = "makepad-git" +version = "0.1.0" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +dependencies = [ + "makepad-fast-inflate", +] + +[[package]] +name = "makepad-half" +version = "2.7.1" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +dependencies = [ + "cfg-if 1.0.4 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", + "crunchy 0.2.4 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", + "num-traits 0.2.20", + "zerocopy 0.8.39", +] + +[[package]] +name = "makepad-html" +version = "0.1.0" +source = "git+https://github.com/OctoSense-org/makepad-html?rev=b16565ae1e56dd7c3a87f00455ae327df599ca3b#b16565ae1e56dd7c3a87f00455ae327df599ca3b" +dependencies = [ + "anyrender", + "anyrender_vello_cpu", + "blitz-dom", + "blitz-html", + "blitz-paint", + "blitz-traits", + "html5ever 0.39.0", + "image", + "makepad-widgets", + "peniko", + "thiserror 2.0.20", +] + +[[package]] +name = "makepad-html" +version = "1.0.0" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +dependencies = [ + "makepad-live-id", +] + +[[package]] +name = "makepad-jni-sys" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9775cbec5fa0647500c3e5de7c850280a88335d1d2d770e5aa2332b801ba7064" + +[[package]] +name = "makepad-latex-math" +version = "0.1.0" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +dependencies = [ + "ttf-parser 0.24.1", +] + +[[package]] +name = "makepad-live-id" +version = "1.0.0" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +dependencies = [ + "makepad-live-id-macros", + "serde", +] + +[[package]] +name = "makepad-live-id-macros" +version = "1.0.0" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +dependencies = [ + "makepad-micro-proc-macro", +] + +[[package]] +name = "makepad-live-reload-core" +version = "0.1.0" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +dependencies = [ + "makepad-filesystem-watcher", +] + +[[package]] +name = "makepad-markdown" +version = "0.1.0" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +dependencies = [ + "blake3", + "comrak", + "emojis", + "html5ever 0.39.0", + "pulldown-cmark 0.13.0", + "unicode-segmentation 1.13.3", + "url", +] + +[[package]] +name = "makepad-markdown-widgets" +version = "0.1.0" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +dependencies = [ + "blake3", + "core-foundation 0.10.1", + "image", + "makepad-latex-math", + "makepad-markdown", + "makepad-widgets", + "mermaid-rs-renderer", + "resvg", + "roxmltree 0.21.1", + "syntect", + "tiny-skia", + "ttf-parser 0.24.1", + "unicode-segmentation 1.12.0", +] + +[[package]] +name = "makepad-math" +version = "1.0.0" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +dependencies = [ + "makepad-micro-serde", +] + +[[package]] +name = "makepad-micro-proc-macro" +version = "1.0.0" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" + +[[package]] +name = "makepad-micro-serde" +version = "1.0.0" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +dependencies = [ + "makepad-live-id", + "makepad-micro-serde-derive", +] + +[[package]] +name = "makepad-micro-serde-derive" +version = "1.0.0" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +dependencies = [ + "makepad-micro-proc-macro", +] + +[[package]] +name = "makepad-network" +version = "1.0.0" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +dependencies = [ + "makepad-apple-sys", + "makepad-error-log", + "makepad-futures-legacy", + "makepad-live-id", + "makepad-micro-serde", + "makepad-script", + "windows 0.62.2 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", +] + +[[package]] +name = "makepad-objc-sys" +version = "1.0.0" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" + +[[package]] +name = "makepad-platform" +version = "2.0.0" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +dependencies = [ + "ash", + "bitflags 2.10.0", + "hilog-sys", + "makepad-android-state", + "makepad-apple-sys", + "makepad-futures", + "makepad-futures-legacy", + "makepad-jni-sys", + "makepad-live-reload-core", + "makepad-network", + "makepad-objc-sys", + "makepad-platform-video", + "makepad-script", + "makepad-script-std", + "makepad-shared-bytes", + "makepad-studio-protocol", + "makepad-tsdf", + "makepad-wasm-bridge", + "makepad-zune-png", + "naga", + "napi-derive-ohos", + "napi-ohos", + "ohos-sys", + "rqrr", + "smallvec 1.15.1 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", + "wayland-client", + "wayland-egl", + "wayland-protocols", + "windows 0.62.2 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", + "windows-core 0.62.2 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", + "windows-targets 0.52.6", +] + +[[package]] +name = "makepad-platform-video" +version = "1.0.0" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +dependencies = [ + "makepad-apple-sys", + "makepad-objc-sys", + "windows 0.62.2 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", +] + +[[package]] +name = "makepad-regex" +version = "0.1.0" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" + +[[package]] +name = "makepad-script" +version = "1.0.0" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +dependencies = [ + "makepad-error-log", + "makepad-html 1.0.0", + "makepad-live-id", + "makepad-math", + "makepad-regex", + "makepad-script-derive", + "makepad-stitch", + "smallvec 1.15.1 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", +] + +[[package]] +name = "makepad-script-derive" +version = "1.0.0" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +dependencies = [ + "makepad-micro-proc-macro", +] + +[[package]] +name = "makepad-script-std" +version = "1.0.0" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +dependencies = [ + "makepad-network", + "makepad-script", +] + +[[package]] +name = "makepad-shared-bytes" +version = "1.0.0" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" + +[[package]] +name = "makepad-stitch" +version = "0.1.0" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" + +[[package]] +name = "makepad-strict-json" +version = "0.1.0" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" + +[[package]] +name = "makepad-studio-protocol" +version = "0.1.0" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +dependencies = [ + "bitflags 2.10.0", + "makepad-error-log", + "makepad-live-id", + "makepad-micro-serde", + "makepad-script", +] + +[[package]] +name = "makepad-svg" +version = "1.0.0" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +dependencies = [ + "makepad-html 1.0.0", + "makepad-live-id", +] + +[[package]] +name = "makepad-tsdf" +version = "0.1.0" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +dependencies = [ + "makepad-math", + "makepad-micro-serde", +] + +[[package]] +name = "makepad-wasm-bridge" +version = "1.0.0" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +dependencies = [ + "makepad-derive-wasm-bridge", + "makepad-live-id", +] + +[[package]] +name = "makepad-webp" +version = "0.2.4" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +dependencies = [ + "makepad-byteorder-lite", +] + +[[package]] +name = "makepad-widgets" +version = "2.0.0" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +dependencies = [ + "makepad-derive-widget", + "makepad-draw", + "makepad-html 1.0.0", + "makepad-latex-math", + "octoscript-node", + "pulldown-cmark 0.12.2", + "serde", + "serde_json", + "ttf-parser 0.24.1", + "unicode-segmentation 1.12.0", +] + +[[package]] +name = "makepad-zune-bmp" +version = "0.5.2" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +dependencies = [ + "makepad-error-log", + "makepad-zune-core", +] + +[[package]] +name = "makepad-zune-core" +version = "0.5.1" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +dependencies = [ + "makepad-error-log", +] + +[[package]] +name = "makepad-zune-inflate" +version = "0.2.54" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +dependencies = [ + "simd-adler32 0.3.9", +] + +[[package]] +name = "makepad-zune-jpeg" +version = "0.5.15" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +dependencies = [ + "makepad-zune-core", +] + +[[package]] +name = "makepad-zune-png" +version = "0.5.2" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +dependencies = [ + "makepad-fast-inflate", + "makepad-zune-core", + "makepad-zune-inflate", +] + +[[package]] +name = "makepad-zune-qoi" +version = "0.5.2" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +dependencies = [ + "makepad-zune-core", +] + +[[package]] +name = "malloc_size_of_derive" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f44db74bde26fdf427af23f1d146c211aed857c59e3be750cf2617f6b0b05c94" +dependencies = [ + "proc-macro2", + "syn 2.0.119", + "synstructure 0.13.2", +] + +[[package]] +name = "maplit" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" + +[[package]] +name = "markup5ever" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "311fe69c934650f8f19652b3946075f0fc41ad8757dbb68f1ca14e7900ecc1c3" +dependencies = [ + "log", + "tendril 0.4.3", + "web_atoms 0.1.3", +] + +[[package]] +name = "markup5ever" +version = "0.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8983d30f2915feeaaab2d6babdd6bc7e9ed1a00b66b5e6d74df19aa9c0e91862" +dependencies = [ + "log", + "tendril 0.5.0", + "web_atoms 0.2.3", +] + +[[package]] +name = "markup5ever" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7122d987ec5f704ee56f6e5b41a7d93722e9aae27ae07cafa4036c4d3f9757de" +dependencies = [ + "log", + "tendril 0.5.0", + "web_atoms 0.2.3", +] + +[[package]] +name = "markup5ever_rcdom" +version = "0.35.0+unofficial" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8bcd53df4748257345b8bc156d620340ce0f015ec1c7ef1cff475543888a31d" +dependencies = [ + "html5ever 0.35.0", + "markup5ever 0.35.0", + "tendril 0.4.3", + "xml5ever 0.35.0", +] + +[[package]] +name = "markup5ever_rcdom" +version = "0.38.0+unofficial" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "333171ccdf66e915257740d44e38ea5b1b19ce7b45d33cc35cb6f118fbd981ff" +dependencies = [ + "html5ever 0.38.0", + "markup5ever 0.38.0", + "tendril 0.5.0", + "xml5ever 0.38.0", +] + +[[package]] +name = "match_token" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac84fd3f360fcc43dc5f5d186f02a94192761a080e8bc58621ad4d12296a58cf" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "matchers" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" +dependencies = [ + "regex-automata", +] + +[[package]] +name = "matchit" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" + +[[package]] +name = "matrix-pickle" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3d65d46b7379dd0afa4a42f9b2269821d31afdee0111b5e0d74e3bee03553a0" +dependencies = [ + "matrix-pickle-derive", + "thiserror 2.0.20", +] + +[[package]] +name = "matrix-pickle-derive" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "414b5e4c34009f2bc3fe35dd018f25755ca38858096574841c7332f99e2c7e77" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "matrix-sdk" +version = "0.18.0" +source = "git+https://github.com/matrix-org/matrix-rust-sdk?rev=6892cb217ae4a886571e928c8efcccfbec5490a6#6892cb217ae4a886571e928c8efcccfbec5490a6" +dependencies = [ + "anymap2", + "as_variant", + "async-channel", + "async-stream", + "async-trait", + "axum", + "backon", + "bytes", + "bytesize", + "cfg-if 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "event-listener", + "eyeball", + "eyeball-im", + "futures-core", + "futures-util", + "gloo-timers 0.4.0", + "hex", + "http", + "imbl", + "indexmap 2.14.2", + "itertools 0.15.0", + "js_int", + "language-tags", + "matrix-sdk-base", + "matrix-sdk-common", + "matrix-sdk-indexeddb", + "matrix-sdk-sqlite", + "mime", + "mime2ext", + "oauth2", + "oauth2-reqwest", + "percent-encoding", + "pin-project-lite", + "rand 0.10.2", + "reqwest 0.13.2", + "ruma", + "serde", + "serde_html_form", + "serde_json", + "sha2 0.11.0", + "tempfile", + "thiserror 2.0.20", + "tokio", + "tokio-stream", + "tokio-util", + "tower", + "tracing", + "url", + "urlencoding", + "vodozemac", + "zeroize", +] + +[[package]] +name = "matrix-sdk-base" +version = "0.18.0" +source = "git+https://github.com/matrix-org/matrix-rust-sdk?rev=6892cb217ae4a886571e928c8efcccfbec5490a6#6892cb217ae4a886571e928c8efcccfbec5490a6" +dependencies = [ + "as_variant", + "async-trait", + "bitflags 2.13.1", + "decancer", + "eyeball", + "eyeball-im", + "futures-util", + "growable-bloom-filter", + "matrix-sdk-common", + "matrix-sdk-crypto", + "matrix-sdk-store-encryption", + "regex", + "ruma", + "serde", + "serde_bytes", + "serde_json", + "thiserror 2.0.20", + "tokio", + "tracing", + "unicode-normalization", +] + +[[package]] +name = "matrix-sdk-common" +version = "0.18.0" +source = "git+https://github.com/matrix-org/matrix-rust-sdk?rev=6892cb217ae4a886571e928c8efcccfbec5490a6#6892cb217ae4a886571e928c8efcccfbec5490a6" +dependencies = [ + "eyeball-im", + "futures-core", + "futures-executor", + "futures-util", + "gloo-timers 0.4.0", + "imbl", + "ruma", + "serde", + "serde_json", + "thiserror 2.0.20", + "tokio", + "tracing", + "tracing-subscriber", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "matrix-sdk-crypto" +version = "0.18.0" +source = "git+https://github.com/matrix-org/matrix-rust-sdk?rev=6892cb217ae4a886571e928c8efcccfbec5490a6#6892cb217ae4a886571e928c8efcccfbec5490a6" +dependencies = [ + "aes 0.9.3", + "as_variant", + "async-trait", + "bs58", + "byteorder 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "ctr 0.10.1", + "eyeball", + "futures-core", + "futures-util", + "hkdf 0.13.0", + "hmac 0.13.0", + "itertools 0.15.0", + "js_option", + "matrix-sdk-common", + "pbkdf2 0.13.0", + "rand 0.10.2", + "rmp-serde", + "ruma", + "serde", + "serde_json", + "sha2 0.11.0", + "subtle", + "thiserror 2.0.20", + "time", + "tokio", + "tokio-stream", + "tracing", + "ulid", + "url", + "vodozemac", + "zeroize", +] + +[[package]] +name = "matrix-sdk-indexeddb" +version = "0.18.0" +source = "git+https://github.com/matrix-org/matrix-rust-sdk?rev=6892cb217ae4a886571e928c8efcccfbec5490a6#6892cb217ae4a886571e928c8efcccfbec5490a6" +dependencies = [ + "async-trait", + "base64 0.23.1", + "futures-util", + "getrandom 0.4.3", + "gloo-utils", + "hkdf 0.13.0", + "js-sys", + "matrix-sdk-base", + "matrix-sdk-crypto", + "matrix-sdk-store-encryption", + "matrix_indexed_db_futures", + "rmp-serde", + "ruma", + "serde", + "serde-wasm-bindgen", + "serde_bytes", + "serde_json", + "sha2 0.11.0", + "thiserror 2.0.20", + "tokio", + "tracing", + "uuid", + "wasm-bindgen", + "web-sys", + "zeroize", +] + +[[package]] +name = "matrix-sdk-sqlite" +version = "0.18.0" +source = "git+https://github.com/matrix-org/matrix-rust-sdk?rev=6892cb217ae4a886571e928c8efcccfbec5490a6#6892cb217ae4a886571e928c8efcccfbec5490a6" +dependencies = [ + "as_variant", + "async-trait", + "deadpool", + "deadpool-sync", + "itertools 0.15.0", + "matrix-sdk-base", + "matrix-sdk-crypto", + "matrix-sdk-store-encryption", + "num_cpus", + "rmp-serde", + "ruma", + "rusqlite", + "serde", + "serde_json", + "serde_path_to_error", + "thiserror 2.0.20", + "tokio", + "tracing", + "vodozemac", + "zeroize", +] + +[[package]] +name = "matrix-sdk-store-encryption" +version = "0.18.0" +source = "git+https://github.com/matrix-org/matrix-rust-sdk?rev=6892cb217ae4a886571e928c8efcccfbec5490a6#6892cb217ae4a886571e928c8efcccfbec5490a6" +dependencies = [ + "base64 0.23.1", + "blake3", + "chacha20poly1305 0.11.0", + "getrandom 0.4.3", + "hkdf 0.13.0", + "hmac 0.13.0", + "pbkdf2 0.13.0", + "rand 0.10.2", + "rmp-serde", + "serde", + "serde_bytes", + "serde_json", + "sha2 0.11.0", + "thiserror 2.0.20", + "zeroize", +] + +[[package]] +name = "matrix-sdk-ui" +version = "0.18.0" +source = "git+https://github.com/matrix-org/matrix-rust-sdk?rev=6892cb217ae4a886571e928c8efcccfbec5490a6#6892cb217ae4a886571e928c8efcccfbec5490a6" +dependencies = [ + "as_variant", + "async-rx", + "async-stream", + "async_cell", + "bitflags 2.13.1", + "chrono", + "emojis", + "eyeball", + "eyeball-im", + "eyeball-im-util", + "futures-core", + "futures-util", + "fuzzy-matcher", + "growable-bloom-filter", + "imbl", + "indexmap 2.14.2", + "itertools 0.15.0", + "matrix-sdk", + "matrix-sdk-base", + "matrix-sdk-common", + "mime", + "pin-project-lite", + "ruma", + "serde", + "serde_json", + "thiserror 2.0.20", + "tokio", + "tokio-stream", + "tracing", + "unicode-normalization", + "unicode-segmentation 1.13.3", +] + +[[package]] +name = "matrix_indexed_db_futures" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245ff6a224b4df7b0c90dda2dd5a6eb46112708d49e8bdd8b007fccb09fea8e4" +dependencies = [ + "accessory", + "cfg-if 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "delegate-display", + "derive_more 2.0.1", + "fancy_constructor", + "futures-core", + "js-sys", + "matrix_indexed_db_futures_macros_internal", + "sealed", + "serde", + "serde-wasm-bindgen", + "smallvec 1.15.1 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 2.0.20", + "tokio", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm_evt_listener", + "web-sys", + "web-time", +] + +[[package]] +name = "matrix_indexed_db_futures_macros_internal" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b428aee5c0fe9e5babd29e99d289b7f64718c444989aac0442d1fd6d3e3f66d1" +dependencies = [ + "macroific", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "maybe-async" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "746873a384ad60adc5db74471dfaba74bd278afbdcfd81db93fafcdfc8b5ca0c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "md-5" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3d65d46b7379dd0afa4a42f9b2269821d31afdee0111b5e0d74e3bee03553a0" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" dependencies = [ - "matrix-pickle-derive", - "thiserror 2.0.20", + "cfg-if 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "digest 0.10.7", ] [[package]] -name = "matrix-pickle-derive" -version = "0.2.3" +name = "memchr" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "414b5e4c34009f2bc3fe35dd018f25755ca38858096574841c7332f99e2c7e77" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" + +[[package]] +name = "memchr" +version = "2.7.6" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" + +[[package]] +name = "memmap2" +version = "0.9.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1219ed1b7f229ee7104d281dd01d6802fe28bb6e95d292942c4daacdeb798c0" dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn 2.0.119", + "libc", ] [[package]] -name = "matrix-sdk" -version = "0.18.0" -source = "git+https://github.com/matrix-org/matrix-rust-sdk#6892cb217ae4a886571e928c8efcccfbec5490a6" +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" dependencies = [ - "anymap2", - "as_variant", - "async-channel", - "async-stream", - "async-trait", - "axum", - "backon", - "bytes", - "bytesize", - "cfg-if 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "event-listener", - "eyeball", - "eyeball-im", - "futures-core", - "futures-util", - "gloo-timers 0.4.0", - "hex", - "http", - "imbl", - "indexmap 2.14.2", - "itertools 0.15.0", - "js_int", - "language-tags", - "matrix-sdk-base", - "matrix-sdk-common", - "matrix-sdk-indexeddb", - "matrix-sdk-sqlite", - "mime", - "mime2ext", - "oauth2", - "oauth2-reqwest", - "percent-encoding", - "pin-project-lite", - "rand 0.10.2", - "reqwest 0.13.2", - "ruma", + "autocfg", +] + +[[package]] +name = "mermaid-rs-renderer" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6cb5b469222ce6b9896edf0a969cf68464f5a028ef394fd6643f00bd943df117" +dependencies = [ + "anyhow", + "fontdb", + "json5", + "once_cell 1.21.4", + "regex", "serde", - "serde_html_form", "serde_json", - "sha2 0.11.0", - "tempfile", "thiserror 2.0.20", + "ttf-parser 0.25.1", +] + +[[package]] +name = "metrics" +version = "0.24.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89550ee9f79e88fef3119de263694973a8adb26c21d75322164fb8c493039fe2" +dependencies = [ + "portable-atomic", + "rapidhash", +] + +[[package]] +name = "metrics-exporter-prometheus" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd7399781913e5393588a8d8c6a2867bf85fb38eaf2502fdce465aad2dc6f034" +dependencies = [ + "base64 0.22.1", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-util", + "indexmap 2.14.2", + "ipnet", + "metrics", + "metrics-util", + "quanta", + "thiserror 1.0.69", "tokio", - "tokio-stream", - "tokio-util", - "tower", "tracing", - "url", - "urlencoding", - "vodozemac", - "zeroize", ] [[package]] -name = "matrix-sdk-base" -version = "0.18.0" -source = "git+https://github.com/matrix-org/matrix-rust-sdk#6892cb217ae4a886571e928c8efcccfbec5490a6" +name = "metrics-util" +version = "0.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8496cc523d1f94c1385dd8f0f0c2c480b2b8aeccb5b7e4485ad6365523ae376" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", + "hashbrown 0.15.5", + "metrics", + "quanta", + "rand 0.9.2", + "rand_xoshiro", + "sketches-ddsketch", +] + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "mime2ext" +version = "0.1.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbf6f36070878c42c5233846cd3de24cf9016828fd47bc22957a687298bb21fc" + +[[package]] +name = "mime_guess" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" +dependencies = [ + "mime", + "unicase 2.8.1", +] + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32 0.3.10", +] + +[[package]] +name = "mio" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b18443e9c262bfe8fa82f51666e2642c53393f7e5c27b3e1aeab922cff5b9d8" +dependencies = [ + "libc", + "wasi 0.11.1+wasi-snapshot-preview1", + "windows-sys 0.61.1", +] + +[[package]] +name = "mmap-rs" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ecce9d566cb9234ae3db9e249c8b55665feaaf32b0859ff1e27e310d2beb3d8" +dependencies = [ + "bitflags 2.13.1", + "combine", + "libc", + "mach2", + "nix 0.30.1", + "sysctl", + "thiserror 2.0.20", + "widestring", + "windows 0.48.0", +] + +[[package]] +name = "moxcms" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb85c154ba489f01b25c0d36ae69a87e4a1c73a72631fc6c0eb6dde34a73e44b" +dependencies = [ + "num-traits 0.2.19", + "pxfm", +] + +[[package]] +name = "multer" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83e87776546dc87511aa5ee218730c92b666d7264ab6ed41f9d215af9cd5224b" +dependencies = [ + "bytes", + "encoding_rs", + "futures-util", + "http", + "httparse", + "memchr 2.7.6 (registry+https://github.com/rust-lang/crates.io-index)", + "mime", + "spin", + "version_check", +] + +[[package]] +name = "multihash" +version = "0.19.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b430e7953c29dd6a09afc29ff0bb69c6e306329ee6794700aee27b76a1aea8d" +dependencies = [ + "core2", + "unsigned-varint", +] + +[[package]] +name = "naga" +version = "27.0.3" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +dependencies = [ + "arrayvec 0.7.6", + "bit-set 0.8.0 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", + "bitflags 2.10.0", + "cfg-if 1.0.4 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", + "cfg_aliases 0.2.1 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", + "hashbrown 0.16.1 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", + "hexf-parse", + "indexmap 2.13.0", + "makepad-error-log", + "makepad-half", + "num-traits 0.2.20", + "once_cell 1.21.3", + "rustc-hash 1.1.0", + "spirv", + "thiserror 2.0.18", + "unicode-ident 1.0.22", +] + +[[package]] +name = "napi-derive-backend-ohos" +version = "0.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6b18d697bedddd2d4c9f8f76b49fe65bd81ed1c55a7eec21ba40c176c236ddc" +dependencies = [ + "convert_case", + "once_cell 1.21.4", + "proc-macro2", + "quote", + "regex", + "syn 2.0.119", +] + +[[package]] +name = "napi-derive-ohos" +version = "0.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8462d74a2d6c7a671bd610f99f9ba34c739aadd2da4d8dd9f109a7e666cc2ad2" +dependencies = [ + "cfg-if 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "convert_case", + "napi-derive-backend-ohos", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "napi-ohos" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad5a3bbb2ae61f345b8c11776f2e79fc2bb71d1901af9a5f81f03c9238a05d86" dependencies = [ - "as_variant", - "async-trait", "bitflags 2.13.1", - "decancer", - "eyeball", - "eyeball-im", - "futures-util", - "growable-bloom-filter", - "matrix-sdk-common", - "matrix-sdk-crypto", - "matrix-sdk-store-encryption", - "regex", - "ruma", - "serde", - "serde_bytes", - "serde_json", - "thiserror 2.0.20", - "tokio", - "tracing", - "unicode-normalization", + "ctor", + "napi-sys-ohos", + "once_cell 1.21.4", ] [[package]] -name = "matrix-sdk-common" -version = "0.18.0" -source = "git+https://github.com/matrix-org/matrix-rust-sdk#6892cb217ae4a886571e928c8efcccfbec5490a6" +name = "napi-sys-ohos" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f101404db01422d034db5afa63eefff6d9c8f66c0894278bc456b4c30954e166" dependencies = [ - "eyeball-im", - "futures-core", - "futures-executor", - "futures-util", - "gloo-timers 0.4.0", - "imbl", - "ruma", - "serde", - "serde_json", - "thiserror 2.0.20", - "tokio", - "tracing", - "tracing-subscriber", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", + "libloading 0.8.8", ] [[package]] -name = "matrix-sdk-crypto" -version = "0.18.0" -source = "git+https://github.com/matrix-org/matrix-rust-sdk#6892cb217ae4a886571e928c8efcccfbec5490a6" +name = "native-tls" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" dependencies = [ - "aes 0.9.3", - "as_variant", - "async-trait", - "bs58", - "byteorder 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "ctr 0.10.1", - "eyeball", - "futures-core", - "futures-util", - "hkdf 0.13.0", - "hmac 0.13.0", - "itertools 0.15.0", - "js_option", - "matrix-sdk-common", - "pbkdf2", - "rand 0.10.2", - "rmp-serde", - "ruma", - "serde", - "serde_json", - "sha2 0.11.0", - "subtle", - "thiserror 2.0.20", - "time", - "tokio", - "tokio-stream", - "tracing", - "ulid", - "url", - "vodozemac", - "zeroize", + "libc", + "log", + "openssl", + "openssl-probe 0.1.6", + "openssl-sys", + "schannel", + "security-framework 2.11.1", + "security-framework-sys", + "tempfile", ] [[package]] -name = "matrix-sdk-indexeddb" -version = "0.18.0" -source = "git+https://github.com/matrix-org/matrix-rust-sdk#6892cb217ae4a886571e928c8efcccfbec5490a6" +name = "ndk-context" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" + +[[package]] +name = "new_debug_unreachable" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" + +[[package]] +name = "nibble_vec" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43" dependencies = [ - "async-trait", - "base64 0.23.1", - "futures-util", - "getrandom 0.4.3", - "gloo-utils", - "hkdf 0.13.0", - "js-sys", - "matrix-sdk-base", - "matrix-sdk-crypto", - "matrix-sdk-store-encryption", - "matrix_indexed_db_futures", - "rmp-serde", - "ruma", - "serde", - "serde-wasm-bindgen", - "serde_bytes", - "serde_json", - "sha2 0.11.0", - "thiserror 2.0.20", - "tokio", - "tracing", - "uuid", - "wasm-bindgen", - "web-sys", - "zeroize", + "smallvec 1.15.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "matrix-sdk-sqlite" -version = "0.18.0" -source = "git+https://github.com/matrix-org/matrix-rust-sdk#6892cb217ae4a886571e928c8efcccfbec5490a6" +name = "nix" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ - "as_variant", - "async-trait", - "deadpool", - "deadpool-sync", - "itertools 0.15.0", - "matrix-sdk-base", - "matrix-sdk-crypto", - "matrix-sdk-store-encryption", - "num_cpus", - "rmp-serde", - "ruma", - "rusqlite", - "serde", - "serde_json", - "serde_path_to_error", - "thiserror 2.0.20", - "tokio", - "tracing", - "vodozemac", - "zeroize", + "bitflags 2.13.1", + "cfg-if 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg_aliases 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", ] [[package]] -name = "matrix-sdk-store-encryption" -version = "0.18.0" -source = "git+https://github.com/matrix-org/matrix-rust-sdk#6892cb217ae4a886571e928c8efcccfbec5490a6" +name = "nix" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" dependencies = [ - "base64 0.23.1", - "blake3", - "chacha20poly1305 0.11.0", - "getrandom 0.4.3", - "hkdf 0.13.0", - "hmac 0.13.0", - "pbkdf2", - "rand 0.10.2", - "rmp-serde", - "serde", - "serde_bytes", - "serde_json", - "sha2 0.11.0", - "thiserror 2.0.20", - "zeroize", + "bitflags 2.13.1", + "cfg-if 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg_aliases 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", ] [[package]] -name = "matrix-sdk-ui" -version = "0.18.0" -source = "git+https://github.com/matrix-org/matrix-rust-sdk#6892cb217ae4a886571e928c8efcccfbec5490a6" +name = "nix" +version = "0.31.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf20d2fde8ff38632c426f1165ed7436270b44f199fc55284c38276f9db47c3d" dependencies = [ - "as_variant", - "async-rx", - "async-stream", - "async_cell", "bitflags 2.13.1", - "chrono", - "emojis", - "eyeball", - "eyeball-im", - "eyeball-im-util", - "futures-core", - "futures-util", - "fuzzy-matcher", - "growable-bloom-filter", - "imbl", - "indexmap 2.14.2", - "itertools 0.15.0", - "matrix-sdk", - "matrix-sdk-base", - "matrix-sdk-common", - "mime", - "pin-project-lite", - "ruma", - "serde", - "serde_json", - "thiserror 2.0.20", - "tokio", - "tokio-stream", - "tracing", - "unicode-normalization", - "unicode-segmentation 1.13.3", + "cfg-if 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg_aliases 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", ] [[package]] -name = "matrix_indexed_db_futures" -version = "0.7.0" +name = "nom" +version = "7.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245ff6a224b4df7b0c90dda2dd5a6eb46112708d49e8bdd8b007fccb09fea8e4" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" dependencies = [ - "accessory", - "cfg-if 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "delegate-display", - "derive_more 2.0.1", - "fancy_constructor", - "futures-core", - "js-sys", - "matrix_indexed_db_futures_macros_internal", - "sealed", - "serde", - "serde-wasm-bindgen", - "smallvec 1.15.1 (registry+https://github.com/rust-lang/crates.io-index)", - "thiserror 2.0.20", - "tokio", - "wasm-bindgen", - "wasm-bindgen-futures", - "wasm_evt_listener", - "web-sys", - "web-time", + "memchr 2.7.6 (registry+https://github.com/rust-lang/crates.io-index)", + "minimal-lexical", ] [[package]] -name = "matrix_indexed_db_futures_macros_internal" -version = "1.0.0" +name = "nom" +version = "8.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b428aee5c0fe9e5babd29e99d289b7f64718c444989aac0442d1fd6d3e3f66d1" +checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405" dependencies = [ - "macroific", - "proc-macro2", - "quote", - "syn 2.0.119", + "memchr 2.7.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "md-5" -version = "0.10.6" +name = "nom_locate" +version = "5.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +checksum = "0b577e2d69827c4740cba2b52efaad1c4cc7c73042860b199710b3575c68438d" dependencies = [ - "cfg-if 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.10.7", + "bytecount", + "memchr 2.7.6 (registry+https://github.com/rust-lang/crates.io-index)", + "nom 8.0.0", ] [[package]] -name = "memchr" -version = "2.7.6" +name = "ntapi" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" - -[[package]] -name = "memchr" -version = "2.7.6" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +checksum = "c3b335231dfd352ffb0f8017f3b6027a4917f7df785ea2143d8af2adc66980ae" +dependencies = [ + "winapi", +] [[package]] -name = "memmap2" -version = "0.9.11" +name = "nu-ansi-term" +version = "0.50.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1219ed1b7f229ee7104d281dd01d6802fe28bb6e95d292942c4daacdeb798c0" +checksum = "d4a28e057d01f97e61255210fcff094d74ed0466038633e95017f5beb68e4399" dependencies = [ - "libc", + "windows-sys 0.52.0", ] [[package]] -name = "memoffset" -version = "0.9.1" +name = "num-bigint" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +checksum = "c89e69e7e0f03bea5ef08013795c25018e101932225a656383bd384495ecc367" dependencies = [ - "autocfg", + "num-integer", + "num-traits 0.2.19", ] [[package]] -name = "mermaid-rs-renderer" -version = "0.3.1" +name = "num-bigint-dig" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cb5b469222ce6b9896edf0a969cf68464f5a028ef394fd6643f00bd943df117" +checksum = "e661dda6640fad38e827a6d4a310ff4763082116fe217f279885c97f511bb0b7" dependencies = [ - "anyhow", - "fontdb", - "json5", - "once_cell 1.21.4", - "regex", - "serde", - "serde_json", - "thiserror 2.0.20", - "ttf-parser 0.25.1", + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits 0.2.19", + "rand 0.8.5", + "smallvec 1.15.1 (registry+https://github.com/rust-lang/crates.io-index)", + "zeroize", ] [[package]] -name = "mime" -version = "0.3.17" +name = "num-conv" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" [[package]] -name = "mime2ext" -version = "0.1.54" +name = "num-derive" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbf6f36070878c42c5233846cd3de24cf9016828fd47bc22957a687298bb21fc" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] [[package]] -name = "mime_guess" -version = "2.0.5" +name = "num-integer" +version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" dependencies = [ - "mime", - "unicase 2.8.1", + "num-traits 0.2.19", ] [[package]] -name = "minimal-lexical" -version = "0.2.1" +name = "num-iter" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits 0.2.19", +] [[package]] -name = "miniz_oxide" -version = "0.8.9" +name = "num-traits" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ - "adler2", - "simd-adler32 0.3.10", + "autocfg", + "libm", ] [[package]] -name = "mio" -version = "1.2.3" +name = "num-traits" +version = "0.2.20" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" + +[[package]] +name = "num_cpus" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b18443e9c262bfe8fa82f51666e2642c53393f7e5c27b3e1aeab922cff5b9d8" +checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" dependencies = [ + "hermit-abi", "libc", - "wasi 0.11.1+wasi-snapshot-preview1", - "windows-sys 0.61.1", ] [[package]] -name = "moxcms" -version = "0.8.1" +name = "oauth2" +version = "5.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb85c154ba489f01b25c0d36ae69a87e4a1c73a72631fc6c0eb6dde34a73e44b" +checksum = "51e219e79014df21a225b1860a479e2dcd7cbd9130f4defd4bd0e191ea31d67d" dependencies = [ - "num-traits 0.2.19", - "pxfm", + "base64 0.22.1", + "chrono", + "getrandom 0.2.16", + "http", + "rand 0.8.5", + "reqwest 0.12.28", + "serde", + "serde_json", + "serde_path_to_error", + "sha2 0.10.9", + "thiserror 1.0.69", + "url", ] [[package]] -name = "multihash" -version = "0.19.3" +name = "oauth2-reqwest" +version = "0.1.0-alpha.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b430e7953c29dd6a09afc29ff0bb69c6e306329ee6794700aee27b76a1aea8d" +checksum = "234fb5c965bbce983ee5de636a7a51d6a3223da8067ea02f9ab2d2d78ac08be2" dependencies = [ - "core2", - "unsigned-varint", + "oauth2", + "reqwest 0.13.2", ] [[package]] -name = "naga" -version = "27.0.3" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +name = "objc2" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a12a8ed07aefc768292f076dc3ac8c48f3781c8f2d5851dd3d98950e8c5a89f" dependencies = [ - "arrayvec 0.7.6", - "bit-set 0.8.0 (git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4)", - "bitflags 2.10.0", - "cfg-if 1.0.4 (git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4)", - "cfg_aliases 0.2.1 (git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4)", - "hashbrown 0.16.1 (git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4)", - "hexf-parse", - "indexmap 2.13.0", - "makepad-error-log", - "makepad-half", - "num-traits 0.2.20", - "once_cell 1.21.3", - "rustc-hash 1.1.0", - "spirv", - "thiserror 2.0.18", - "unicode-ident 1.0.22", + "objc2-encode", ] [[package]] -name = "napi-derive-backend-ohos" -version = "0.0.7" +name = "objc2-app-kit" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6b18d697bedddd2d4c9f8f76b49fe65bd81ed1c55a7eec21ba40c176c236ddc" +checksum = "d49e936b501e5c5bf01fda3a9452ff86dc3ea98ad5f283e1455153142d97518c" dependencies = [ - "convert_case", - "once_cell 1.21.4", - "proc-macro2", - "quote", - "regex", - "syn 2.0.119", + "bitflags 2.13.1", + "block2", + "objc2", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-foundation", ] [[package]] -name = "napi-derive-ohos" -version = "0.0.9" +name = "objc2-authentication-services" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8462d74a2d6c7a671bd610f99f9ba34c739aadd2da4d8dd9f109a7e666cc2ad2" +checksum = "ee6d6f7dab884a28adaec1012eb3889257a49cc145724e35f93ece2d209f8b25" dependencies = [ - "cfg-if 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "convert_case", - "napi-derive-backend-ohos", - "proc-macro2", - "quote", - "syn 2.0.119", + "block2", + "objc2", + "objc2-app-kit", + "objc2-foundation", ] [[package]] -name = "napi-ohos" -version = "0.1.3" +name = "objc2-core-foundation" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad5a3bbb2ae61f345b8c11776f2e79fc2bb71d1901af9a5f81f03c9238a05d86" +checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" dependencies = [ "bitflags 2.13.1", - "ctor", - "napi-sys-ohos", - "once_cell 1.21.4", + "dispatch2", + "objc2", ] [[package]] -name = "napi-sys-ohos" -version = "0.0.1" +name = "objc2-core-graphics" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f101404db01422d034db5afa63eefff6d9c8f66c0894278bc456b4c30954e166" +checksum = "e022c9d066895efa1345f8e33e584b9f958da2fd4cd116792e15e07e4720a807" dependencies = [ - "libloading 0.8.8", + "bitflags 2.13.1", + "dispatch2", + "objc2", + "objc2-core-foundation", + "objc2-io-surface", ] [[package]] -name = "native-tls" -version = "0.2.14" +name = "objc2-core-location" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" +checksum = "ca347214e24bc973fc025fd0d36ebb179ff30536ed1f80252706db19ee452009" dependencies = [ - "libc", - "log", - "openssl", - "openssl-probe 0.1.6", - "openssl-sys", - "schannel", - "security-framework 2.11.1", - "security-framework-sys", - "tempfile", + "objc2", + "objc2-foundation", ] [[package]] -name = "ndk-context" -version = "0.1.1" +name = "objc2-core-text" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" +checksum = "0cde0dfb48d25d2b4862161a4d5fcc0e3c24367869ad306b0c9ec0073bfed92d" +dependencies = [ + "bitflags 2.13.1", + "objc2-core-foundation", +] [[package]] -name = "new_debug_unreachable" -version = "1.0.6" +name = "objc2-encode" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" +checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" [[package]] -name = "nom" -version = "7.1.3" +name = "objc2-foundation" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" dependencies = [ - "memchr 2.7.6 (registry+https://github.com/rust-lang/crates.io-index)", - "minimal-lexical", + "bitflags 2.13.1", + "block2", + "objc2", + "objc2-core-foundation", ] [[package]] -name = "nu-ansi-term" -version = "0.50.1" +name = "objc2-io-surface" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4a28e057d01f97e61255210fcff094d74ed0466038633e95017f5beb68e4399" +checksum = "180788110936d59bab6bd83b6060ffdfffb3b922ba1396b312ae795e1de9d81d" dependencies = [ - "windows-sys 0.52.0", + "bitflags 2.13.1", + "objc2", + "objc2-core-foundation", ] [[package]] -name = "num-bigint-dig" -version = "0.8.6" +name = "objc2-photos-ui" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e661dda6640fad38e827a6d4a310ff4763082116fe217f279885c97f511bb0b7" +checksum = "fdddde9dfb986546746e3115021a85c4a83e1c5e9037b3c865a688fe9bf94ebb" dependencies = [ - "lazy_static", - "libm", - "num-integer", - "num-iter", - "num-traits 0.2.19", - "rand 0.8.5", - "smallvec 1.15.1 (registry+https://github.com/rust-lang/crates.io-index)", - "zeroize", + "bitflags 2.13.1", + "objc2", + "objc2-foundation", ] [[package]] -name = "num-conv" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" - -[[package]] -name = "num-derive" -version = "0.4.2" +name = "objc2-ui-kit" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +checksum = "d87d638e33c06f577498cbcc50491496a3ed4246998a7fbba7ccb98b1e7eab22" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", + "bitflags 2.13.1", + "block2", + "objc2", + "objc2-core-foundation", + "objc2-foundation", + "objc2-uniform-type-identifiers", ] [[package]] -name = "num-integer" -version = "0.1.46" +name = "objc2-uniform-type-identifiers" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +checksum = "7902ac02859fc1f7045f8b598c63f1ae0cc7efeaa06a9bc9f3d9a3c955974fa4" dependencies = [ - "num-traits 0.2.19", + "objc2", + "objc2-foundation", ] [[package]] -name = "num-iter" -version = "0.1.45" +name = "object" +version = "0.37.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" dependencies = [ - "autocfg", - "num-integer", - "num-traits 0.2.19", + "memchr 2.7.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +name = "octos-agent" +version = "2.0.3-rc.12" +source = "git+https://github.com/octos-org/octos.git?rev=18fcd3f16e527d2b601d7ae244f056fb711bb6b8#18fcd3f16e527d2b601d7ae244f056fb711bb6b8" dependencies = [ - "autocfg", - "libm", + "async-trait", + "base64 0.22.1", + "chromiumoxide", + "chrono", + "dirs", + "dunce", + "eyre", + "flate2", + "futures", + "gix", + "glob", + "globset", + "hound", + "htmd", + "html5ever 0.35.0", + "ignore", + "keyring", + "lettre", + "libc", + "markup5ever_rcdom 0.35.0+unofficial", + "metrics", + "oauth2", + "octos-bus", + "octos-core", + "octos-llm", + "octos-memory", + "octos-plugin", + "pdf-extract", + "redb", + "regex", + "reqwest 0.12.28", + "reqwest 0.13.2", + "rmcp", + "rustix", + "serde", + "serde_json", + "sha2 0.10.9", + "shlex", + "similar", + "tar", + "tempfile", + "tiny_http", + "tokio", + "tokio-util", + "toml 0.8.23", + "tracing", + "tree-sitter", + "tree-sitter-javascript", + "tree-sitter-python", + "tree-sitter-rust", + "tree-sitter-typescript", + "url", + "webbrowser", + "which 7.0.3", ] [[package]] -name = "num-traits" -version = "0.2.20" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +name = "octos-app-transport" +version = "0.1.0" +source = "git+https://github.com/OctoSense-org/OctoSense-System-Apps.git?rev=1576bec6a585758e48c3252030cad2a9bf9c80db#1576bec6a585758e48c3252030cad2a9bf9c80db" +dependencies = [ + "android_logger", + "chrono", + "futures-util", + "log", + "octos-cli", + "octos-core", + "reqwest 0.12.28", + "serde", + "serde_json", + "tokio", + "tokio-tungstenite 0.24.0", + "tracing-subscriber", + "url", + "uuid", +] [[package]] -name = "num_cpus" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" +name = "octos-bus" +version = "2.0.3-rc.12" +source = "git+https://github.com/octos-org/octos.git?rev=18fcd3f16e527d2b601d7ae244f056fb711bb6b8#18fcd3f16e527d2b601d7ae244f056fb711bb6b8" dependencies = [ - "hermit-abi", - "libc", + "aes 0.8.4", + "async-trait", + "axum", + "base64 0.22.1", + "cbc 0.1.2", + "chrono", + "chrono-tz", + "cron", + "eyre", + "futures", + "lru", + "metrics", + "octos-core", + "reqwest 0.12.28", + "serde", + "serde_json", + "serde_yml", + "sha2 0.10.9", + "subtle", + "tokio", + "tracing", + "uuid", ] [[package]] -name = "oauth2" -version = "5.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51e219e79014df21a225b1860a479e2dcd7cbd9130f4defd4bd0e191ea31d67d" +name = "octos-cli" +version = "2.0.3-rc.12" +source = "git+https://github.com/octos-org/octos.git?rev=18fcd3f16e527d2b601d7ae244f056fb711bb6b8#18fcd3f16e527d2b601d7ae244f056fb711bb6b8" dependencies = [ + "agent-client-protocol", + "argon2", + "async-trait", + "axum", "base64 0.22.1", + "chacha20poly1305 0.10.1", "chrono", + "clap", + "clap_complete", + "color-eyre", + "colored", + "constant_time_eq 0.3.1", + "dirs", + "dunce", + "eyre", + "flate2", + "fs2", + "futures", "getrandom 0.2.16", - "http", + "iana-time-zone", + "image", + "keyring", + "lettre", + "libc", + "metrics", + "metrics-exporter-prometheus", + "octos-agent", + "octos-bus", + "octos-core", + "octos-diagnostics", + "octos-fleet", + "octos-fleet-worker", + "octos-llm", + "octos-memory", + "octos-pipeline", + "octos-plugin", + "octos-sandbox", + "octos-services", + "octos-store", + "octos-swarm", + "octos-workflows", + "open", + "percent-encoding", + "qrcode", + "quick-xml", "rand 0.8.5", + "redb", + "regex", + "reqwest 0.12.28", + "rpassword", + "rust-embed", + "rustix", + "rustls", + "rustls-native-certs", + "rustyline", "serde", "serde_json", - "serde_path_to_error", "sha2 0.10.9", - "thiserror 1.0.69", + "subtle", + "sysinfo", + "tar", + "tempfile", + "tokio", + "tokio-tungstenite 0.26.2", + "tokio-util", + "toml 0.8.23", + "tower-http", + "tracing", + "tracing-appender", + "tracing-subscriber", "url", + "uuid", + "zip", ] [[package]] -name = "oauth2-reqwest" -version = "0.1.0-alpha.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "234fb5c965bbce983ee5de636a7a51d6a3223da8067ea02f9ab2d2d78ac08be2" +name = "octos-core" +version = "2.0.3-rc.12" +source = "git+https://github.com/octos-org/octos.git?rev=18fcd3f16e527d2b601d7ae244f056fb711bb6b8#18fcd3f16e527d2b601d7ae244f056fb711bb6b8" dependencies = [ - "oauth2", - "reqwest 0.13.2", + "chrono", + "eyre", + "serde", + "serde_json", + "sha2 0.10.9", + "tracing", + "uuid", ] [[package]] -name = "objc2" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a12a8ed07aefc768292f076dc3ac8c48f3781c8f2d5851dd3d98950e8c5a89f" +name = "octos-diagnostics" +version = "2.0.3-rc.12" +source = "git+https://github.com/octos-org/octos.git?rev=18fcd3f16e527d2b601d7ae244f056fb711bb6b8#18fcd3f16e527d2b601d7ae244f056fb711bb6b8" dependencies = [ - "objc2-encode", + "eyre", + "octos-core", + "reqwest 0.12.28", + "serde", + "serde_json", ] [[package]] -name = "objc2-app-kit" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d49e936b501e5c5bf01fda3a9452ff86dc3ea98ad5f283e1455153142d97518c" +name = "octos-fleet" +version = "2.0.3-rc.12" +source = "git+https://github.com/octos-org/octos.git?rev=18fcd3f16e527d2b601d7ae244f056fb711bb6b8#18fcd3f16e527d2b601d7ae244f056fb711bb6b8" dependencies = [ - "bitflags 2.13.1", - "block2", - "objc2", - "objc2-core-foundation", - "objc2-core-graphics", - "objc2-foundation", + "eyre", + "octos-core", + "redb", + "rusqlite", + "serde", + "serde_json", + "tokio", + "tracing", + "uuid", ] [[package]] -name = "objc2-authentication-services" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee6d6f7dab884a28adaec1012eb3889257a49cc145724e35f93ece2d209f8b25" +name = "octos-fleet-worker" +version = "2.0.3-rc.12" +source = "git+https://github.com/octos-org/octos.git?rev=18fcd3f16e527d2b601d7ae244f056fb711bb6b8#18fcd3f16e527d2b601d7ae244f056fb711bb6b8" dependencies = [ - "block2", - "objc2", - "objc2-app-kit", - "objc2-foundation", + "async-trait", + "eyre", + "octos-agent", + "octos-core", + "octos-fleet", + "octos-llm", + "octos-memory", + "serde_json", + "tokio", + "tracing", +] + +[[package]] +name = "octos-llm" +version = "2.0.3-rc.12" +source = "git+https://github.com/octos-org/octos.git?rev=18fcd3f16e527d2b601d7ae244f056fb711bb6b8#18fcd3f16e527d2b601d7ae244f056fb711bb6b8" +dependencies = [ + "async-trait", + "base64 0.22.1", + "chrono", + "eyre", + "futures", + "jsonwebtoken", + "libc", + "metrics", + "octos-core", + "redb", + "reqwest 0.12.28", + "secrecy", + "serde", + "serde_json", + "sha2 0.10.9", + "tokio", + "tracing", +] + +[[package]] +name = "octos-memory" +version = "2.0.3-rc.12" +source = "git+https://github.com/octos-org/octos.git?rev=18fcd3f16e527d2b601d7ae244f056fb711bb6b8#18fcd3f16e527d2b601d7ae244f056fb711bb6b8" +dependencies = [ + "bincode", + "chrono", + "eyre", + "hnsw_rs", + "octos-core", + "redb", + "regex", + "serde", + "serde_json", + "tokio", + "tracing", + "uuid", ] [[package]] -name = "objc2-core-foundation" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" +name = "octos-pipeline" +version = "2.0.3-rc.12" +source = "git+https://github.com/octos-org/octos.git?rev=18fcd3f16e527d2b601d7ae244f056fb711bb6b8#18fcd3f16e527d2b601d7ae244f056fb711bb6b8" dependencies = [ - "bitflags 2.13.1", - "dispatch2", - "objc2", + "async-trait", + "chrono", + "eyre", + "futures", + "glob", + "octos-agent", + "octos-core", + "octos-llm", + "octos-memory", + "octos-plugin", + "regex", + "serde", + "serde_json", + "tokio", + "tracing", ] [[package]] -name = "objc2-core-graphics" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e022c9d066895efa1345f8e33e584b9f958da2fd4cd116792e15e07e4720a807" +name = "octos-plugin" +version = "2.0.3-rc.12" +source = "git+https://github.com/octos-org/octos.git?rev=18fcd3f16e527d2b601d7ae244f056fb711bb6b8#18fcd3f16e527d2b601d7ae244f056fb711bb6b8" dependencies = [ - "bitflags 2.13.1", - "dispatch2", - "objc2", - "objc2-core-foundation", - "objc2-io-surface", + "eyre", + "metrics", + "serde", + "serde_json", + "tokio", + "tracing", + "which 7.0.3", ] [[package]] -name = "objc2-core-location" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca347214e24bc973fc025fd0d36ebb179ff30536ed1f80252706db19ee452009" +name = "octos-sandbox" +version = "0.1.0" +source = "git+https://github.com/octos-org/octos.git?rev=18fcd3f16e527d2b601d7ae244f056fb711bb6b8#18fcd3f16e527d2b601d7ae244f056fb711bb6b8" dependencies = [ - "objc2", - "objc2-foundation", + "clap", + "eyre", + "landlock", + "lddtree", + "libc", + "rappct", + "seccompiler", + "windows 0.62.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "objc2-core-text" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cde0dfb48d25d2b4862161a4d5fcc0e3c24367869ad306b0c9ec0073bfed92d" +name = "octos-services" +version = "2.0.3-rc.12" +source = "git+https://github.com/octos-org/octos.git?rev=18fcd3f16e527d2b601d7ae244f056fb711bb6b8#18fcd3f16e527d2b601d7ae244f056fb711bb6b8" dependencies = [ - "bitflags 2.13.1", - "objc2-core-foundation", + "chrono", + "dirs", + "eyre", + "flate2", + "futures", + "octos-bus", + "octos-core", + "octos-llm", + "reqwest 0.12.28", + "serde", + "serde_json", + "tar", + "tokio", + "tracing", ] [[package]] -name = "objc2-encode" -version = "4.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" +name = "octos-store" +version = "2.0.3-rc.12" +source = "git+https://github.com/octos-org/octos.git?rev=18fcd3f16e527d2b601d7ae244f056fb711bb6b8#18fcd3f16e527d2b601d7ae244f056fb711bb6b8" +dependencies = [ + "base64 0.22.1", + "chrono", + "constant_time_eq 0.3.1", + "eyre", + "getrandom 0.2.16", + "octos-core", + "redb", + "serde", + "serde_json", + "sha2 0.10.9", + "tokio", + "tracing", + "uuid", +] [[package]] -name = "objc2-foundation" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" +name = "octos-swarm" +version = "2.0.3-rc.12" +source = "git+https://github.com/octos-org/octos.git?rev=18fcd3f16e527d2b601d7ae244f056fb711bb6b8#18fcd3f16e527d2b601d7ae244f056fb711bb6b8" dependencies = [ - "bitflags 2.13.1", - "block2", - "objc2", - "objc2-core-foundation", + "async-trait", + "chrono", + "eyre", + "metrics", + "octos-agent", + "redb", + "serde", + "serde_json", + "sha2 0.10.9", + "tokio", + "tracing", + "uuid", ] [[package]] -name = "objc2-io-surface" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "180788110936d59bab6bd83b6060ffdfffb3b922ba1396b312ae795e1de9d81d" +name = "octos-workflows" +version = "2.0.3-rc.12" +source = "git+https://github.com/octos-org/octos.git?rev=18fcd3f16e527d2b601d7ae244f056fb711bb6b8#18fcd3f16e527d2b601d7ae244f056fb711bb6b8" dependencies = [ - "bitflags 2.13.1", - "objc2", - "objc2-core-foundation", + "chrono", + "eyre", + "octos-agent", + "octos-core", + "octos-pipeline", + "serde", + "serde_json", + "tokio", + "tracing", ] [[package]] -name = "objc2-photos-ui" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdddde9dfb986546746e3115021a85c4a83e1c5e9037b3c865a688fe9bf94ebb" +name = "octoscript-makepad" +version = "0.1.0" +source = "git+https://www.github.com/OctoSense-org/Octoscript-Makepad.git?rev=b9034566b0607c5bb8c04134d17139f99989e1d0#b9034566b0607c5bb8c04134d17139f99989e1d0" dependencies = [ - "bitflags 2.13.1", - "objc2", - "objc2-foundation", + "octoscript-render", + "octoscript-ui-l0", + "serde_json", ] [[package]] -name = "objc2-ui-kit" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d87d638e33c06f577498cbcc50491496a3ed4246998a7fbba7ccb98b1e7eab22" +name = "octoscript-node" +version = "0.1.0" +source = "git+https://www.github.com/OctoSense-org/Octoscript-Makepad.git?rev=b9034566b0607c5bb8c04134d17139f99989e1d0#b9034566b0607c5bb8c04134d17139f99989e1d0" + +[[package]] +name = "octoscript-render" +version = "0.1.0" +source = "git+https://www.github.com/OctoSense-org/Octoscript-Makepad.git?rev=b9034566b0607c5bb8c04134d17139f99989e1d0#b9034566b0607c5bb8c04134d17139f99989e1d0" dependencies = [ - "bitflags 2.13.1", - "block2", - "objc2", - "objc2-core-foundation", - "objc2-foundation", - "objc2-uniform-type-identifiers", + "makepad-script", + "octoscript-node", + "serde_json", ] [[package]] -name = "objc2-uniform-type-identifiers" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7902ac02859fc1f7045f8b598c63f1ae0cc7efeaa06a9bc9f3d9a3c955974fa4" +name = "octoscript-ui-l0" +version = "0.1.0" +source = "git+https://www.github.com/OctoSense-org/Octoscript.git?rev=68f6a9df55692b5d8ef8873a12721e279a3f40d6#68f6a9df55692b5d8ef8873a12721e279a3f40d6" dependencies = [ - "objc2", - "objc2-foundation", + "blake3", + "serde_json", ] [[package]] -name = "octoscript-node" +name = "octoscript-widgets" version = "0.1.0" -source = "git+https://github.com/OctoSense-org/Octoscript-Makepad.git?rev=78f90f6e9e5e3b9fe4b5f5b0618fa4e93db30860#78f90f6e9e5e3b9fe4b5f5b0618fa4e93db30860" +source = "git+https://www.github.com/OctoSense-org/Octoscript-Makepad.git?rev=b9034566b0607c5bb8c04134d17139f99989e1d0#b9034566b0607c5bb8c04134d17139f99989e1d0" +dependencies = [ + "makepad-widgets", + "serde_json", +] [[package]] -name = "octoscript-ui-l0" +name = "octosense-app-policy" version = "0.1.0" -source = "git+https://github.com/OctoSense-org/Octoscript?rev=86a51a30767da5bf1f2e87559730f8539300b5d0#86a51a30767da5bf1f2e87559730f8539300b5d0" +source = "git+https://github.com/OctoSense-org/OctoSense-App-Hub.git?rev=b0591e2caa0dc5c62927f7b85dbf826a50618a03#b0591e2caa0dc5c62927f7b85dbf826a50618a03" dependencies = [ "blake3", + "makepad-widgets", + "serde", "serde_json", ] @@ -5453,7 +7961,7 @@ checksum = "8d380ab6c951261a0e44306245bc960b3b3367f099a7da7156bd1a3cacaf783c" [[package]] name = "once_cell" version = "1.21.3" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "once_cell" @@ -5473,6 +7981,16 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" +[[package]] +name = "open" +version = "5.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa576c76302b7b808eecc68061e67336c47833ef9d22caa74dda10fa9675eebc" +dependencies = [ + "is-wsl", + "libc", +] + [[package]] name = "openssl" version = "0.10.75" @@ -5539,6 +8057,12 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "owo-colors" +version = "4.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c45bb4a6ae1280ec0803b1ef9d3455eb50f01efbbe1447ab020f1d54fba9d8" + [[package]] name = "p256" version = "0.13.2" @@ -5647,6 +8171,22 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35fb2e5f958ec131621fdd531e9fc186ed768cbe395337403ae56c17a74c68ec" +[[package]] +name = "pastey" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ee67f1008b1ba2321834326597b8e186293b049a023cdef258527550b9935b4" + +[[package]] +name = "pbkdf2" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" +dependencies = [ + "digest 0.10.7", + "hmac 0.12.1", +] + [[package]] name = "pbkdf2" version = "0.13.0" @@ -5656,6 +8196,33 @@ dependencies = [ "digest 0.11.3", ] +[[package]] +name = "pdf-extract" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c2f44c6c642e359e2fe7f662bf5438db3811b6b4be60afc6de04b619ce51e1a" +dependencies = [ + "adobe-cmap-parser", + "cff-parser", + "encoding_rs", + "euclid 0.20.14", + "log", + "lopdf", + "postscript", + "type1-encoding-parser", + "unicode-normalization", +] + +[[package]] +name = "pem" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d30c53c26bc5b31a98cd02d20f25a7c8567146caf63ed593a9d87b2775291be" +dependencies = [ + "base64 0.22.1", + "serde_core", +] + [[package]] name = "pem-rfc7468" version = "0.7.0" @@ -5693,6 +8260,15 @@ dependencies = [ "phf_shared 0.11.3", ] +[[package]] +name = "phf" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "913273894cec178f401a31ec4b656318d95473527be05c0752cc41cdc32be8b7" +dependencies = [ + "phf_shared 0.12.1", +] + [[package]] name = "phf" version = "0.13.1" @@ -5766,6 +8342,15 @@ dependencies = [ "siphasher", ] +[[package]] +name = "phf_shared" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06005508882fb681fd97892ecff4b7fd0fee13ef1aa569f8695dae7ab9099981" +dependencies = [ + "siphasher", +] + [[package]] name = "phf_shared" version = "0.13.1" @@ -5781,6 +8366,26 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" +[[package]] +name = "pin-project" +version = "1.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2466b2336ed02bcdca6b294417127b90ec92038d1d5c4fbeac971a922e0e0924" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c96395f0a926bc13b1c17622aaddda1ecb55d49c8f1bf9777e4d877800a43f8b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + [[package]] name = "pin-project-lite" version = "0.2.17" @@ -5834,7 +8439,13 @@ checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" [[package]] name = "pkg-config" version = "0.3.32" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" + +[[package]] +name = "plain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" [[package]] name = "png" @@ -5924,6 +8535,33 @@ dependencies = [ "universal-hash 0.5.1", ] +[[package]] +name = "pom" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60f6ce597ecdcc9a098e7fddacb1065093a3d66446fa16c675e7e71d1b5c28e6" + +[[package]] +name = "portable-atomic" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05c8b63e8d9609db387f0324918f81d68fe27748f084ef092fb35954d0539a85" + +[[package]] +name = "portable-atomic-util" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10ab3eb7f3becc3a1cbc4f2c6f20267996cfc1a6467a873763411b136a122715" +dependencies = [ + "portable-atomic", +] + +[[package]] +name = "postscript" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78451badbdaebaf17f053fd9152b3ffb33b516104eacb45e7864aaa9c712f306" + [[package]] name = "potential_utf" version = "0.1.3" @@ -5980,7 +8618,7 @@ version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" dependencies = [ - "toml_edit", + "toml_edit 0.23.4", ] [[package]] @@ -5992,6 +8630,29 @@ dependencies = [ "unicode-ident 1.0.19", ] +[[package]] +name = "process-wrap" +version = "9.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f95f6259ebd0640685b7cd26d635861f39208df0f89b2b61ff5cf76310fa54f6" +dependencies = [ + "futures", + "indexmap 2.14.2", + "nix 0.31.3", + "tokio", + "tracing", + "windows 0.62.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "prodash" +version = "31.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "962200e2d7d551451297d9fdce85138374019ada198e30ea9ede38034e27604c" +dependencies = [ + "parking_lot", +] + [[package]] name = "prost" version = "0.14.4" @@ -6018,10 +8679,10 @@ dependencies = [ [[package]] name = "pulldown-cmark" version = "0.12.2" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "bitflags 2.10.0", - "memchr 2.7.6 (git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4)", + "memchr 2.7.6 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", "unicase 2.9.0", ] @@ -6045,10 +8706,31 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "007d8adb5ddab6f8e3f491ac63566a7d5002cc7ed73901f72057943fa71ae1ae" [[package]] -name = "pxfm" -version = "0.1.30" +name = "pxfm" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d55d956fa96f5ec02be2e13af0e20391a5aa83d6a074e3ad368959d0fab299ea" + +[[package]] +name = "qrcode" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d68782463e408eb1e668cf6152704bd856c78c5b6417adaee3203d8f4c1fc9ec" + +[[package]] +name = "quanta" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d55d956fa96f5ec02be2e13af0e20391a5aa83d6a074e3ad368959d0fab299ea" +checksum = "f3ab5a9d756f0d97bdc89019bd2e4ea098cf9cde50ee7564dde6b81ccc8f06c7" +dependencies = [ + "crossbeam-utils", + "libc", + "once_cell 1.21.4", + "raw-cpuid", + "wasi 0.11.1+wasi-snapshot-preview1", + "web-sys", + "winapi", +] [[package]] name = "quick-error" @@ -6056,6 +8738,15 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" +[[package]] +name = "quick-xml" +version = "0.37.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "331e97a1af0bf59823e6eadffe373d7b27f485be8748f71471c662c1f269b7fb" +dependencies = [ + "memchr 2.7.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "quinn" version = "0.11.9" @@ -6121,6 +8812,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "quoted_printable" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "478e0585659a122aa407eb7e3c0e1fa51b1d8a870038bd29f0cf4a8551eea972" + [[package]] name = "r-efi" version = "5.3.0" @@ -6133,6 +8830,16 @@ version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" +[[package]] +name = "radix_trie" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd" +dependencies = [ + "endian-type", + "nibble_vec", +] + [[package]] name = "rand" version = "0.8.5" @@ -6224,6 +8931,34 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f93e7e49bb0bf967717f7bd674458b3d6b0c5f48ec7e3038166026a69fc22223" +[[package]] +name = "rapidhash" +version = "4.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5da7e78a036ce858e8d55b7e7dc8ba3a88b78350fd2155d3591bbd966b58589e" +dependencies = [ + "rustversion", +] + +[[package]] +name = "rappct" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11762a6aea3b0a87a51b21cb2085d252f10c01cd0f3f505e1da002cf6e2427da" +dependencies = [ + "thiserror 2.0.20", + "windows 0.62.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "raw-cpuid" +version = "11.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "498cd0dc59d73224351ee52a95fee0f1a617a2eae0e7d9d720cc622c73a54186" +dependencies = [ + "bitflags 2.13.1", +] + [[package]] name = "raw-window-handle" version = "0.6.2" @@ -6276,6 +9011,15 @@ dependencies = [ "tokio", ] +[[package]] +name = "redb" +version = "2.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eca1e9d98d5a7e9002d0013e18d5a9b000aee942eb134883a82f06ebffb6c01" +dependencies = [ + "libc", +] + [[package]] name = "redox_syscall" version = "0.5.17" @@ -6285,6 +9029,17 @@ dependencies = [ "bitflags 2.13.1", ] +[[package]] +name = "redox_users" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" +dependencies = [ + "getrandom 0.2.16", + "libredox", + "thiserror 1.0.69", +] + [[package]] name = "redox_users" version = "0.5.2" @@ -6354,6 +9109,7 @@ dependencies = [ "base64 0.22.1", "bytes", "encoding_rs", + "futures-channel", "futures-core", "futures-util", "h2", @@ -6367,6 +9123,7 @@ dependencies = [ "js-sys", "log", "mime", + "mime_guess", "native-tls", "percent-encoding", "pin-project-lite", @@ -6390,6 +9147,7 @@ dependencies = [ "wasm-bindgen-futures", "wasm-streams 0.4.2", "web-sys", + "webpki-roots", ] [[package]] @@ -6417,6 +9175,8 @@ dependencies = [ "rustls", "rustls-pki-types", "rustls-platform-verifier", + "serde", + "serde_json", "sync_wrapper", "tokio", "tokio-rustls", @@ -6547,6 +9307,11 @@ dependencies = [ "mime", "mime_guess", "num_cpus", + "octos-app-transport", + "octoscript-makepad", + "octoscript-ui-l0", + "octoscript-widgets", + "octosense-app-policy", "percent-encoding", "pulldown-cmark 0.13.0", "quinn", @@ -6554,6 +9319,7 @@ dependencies = [ "rangemap", "reqwest 0.12.28", "rfd", + "rinx-miniapp-core", "robius-directories", "robius-file-picker", "robius-location", @@ -6569,15 +9335,72 @@ dependencies = [ "sha2 0.10.9", "thiserror 2.0.20", "tokio", - "toml", + "toml 1.1.2+spec-1.1.0", "tracing-subscriber", "tsp_sdk", "unicode-segmentation 1.13.3", "url", + "uuid", "webpki-root-certs", "winresource", ] +[[package]] +name = "rinx-miniapp-core" +version = "0.1.0" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "rmcp" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1f571c72940a19d9532fe52dbea8bc9912bf1d766c2970bb824056b86f3f59" +dependencies = [ + "async-trait", + "base64 0.22.1", + "bytes", + "chrono", + "futures", + "http", + "http-body", + "http-body-util", + "oauth2", + "pastey 0.2.3", + "pin-project-lite", + "process-wrap", + "rand 0.10.2", + "reqwest 0.13.2", + "rmcp-macros", + "schemars 1.1.0", + "serde", + "serde_json", + "sse-stream", + "thiserror 2.0.20", + "tokio", + "tokio-stream", + "tokio-util", + "tower-service", + "tracing", + "url", + "uuid", +] + +[[package]] +name = "rmcp-macros" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aad0035b69380782d78ea95b508327e6deaa2235909053e596eea8f27b5e1d5" +dependencies = [ + "darling 0.23.0", + "proc-macro2", + "quote", + "serde_json", + "syn 2.0.119", +] + [[package]] name = "rmp" version = "0.8.14" @@ -6605,7 +9428,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "087fcb3061ccc432658a605cb868edd44e0efb08e7a159b486f02804a7616bef" dependencies = [ - "jni", + "jni 0.21.1", "makepad-android-state", "ndk-context", ] @@ -6620,8 +9443,8 @@ name = "robius-directories" version = "6.0.1" source = "git+https://github.com/project-robius/robius#cca3cc3dc99d8fcb6c69a127cd28d47ba8f3e3eb" dependencies = [ - "dirs-sys", - "jni", + "dirs-sys 0.5.0", + "jni 0.21.1", "robius-android-env", ] @@ -6634,7 +9457,7 @@ dependencies = [ "block2", "cfg-if 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "dispatch2", - "jni", + "jni 0.21.1", "mime_guess", "objc2", "objc2-foundation", @@ -6654,7 +9477,7 @@ source = "git+https://github.com/project-robius/robius#cca3cc3dc99d8fcb6c69a127c dependencies = [ "android-build", "cfg-if 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "jni", + "jni 0.21.1", "objc2", "objc2-core-location", "objc2-foundation", @@ -6671,7 +9494,7 @@ dependencies = [ "block2", "cfg-if 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "dispatch2", - "jni", + "jni 0.21.1", "objc2", "objc2-app-kit", "objc2-foundation", @@ -6688,7 +9511,7 @@ dependencies = [ "android-build", "cfg-if 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "dispatch2", - "jni", + "jni 0.21.1", "libc", "objc2", "objc2-app-kit", @@ -6704,7 +9527,7 @@ name = "robius-speech" version = "0.3.1" source = "git+https://github.com/project-robius/robius?rev=166991b1b18188ee2d8441f7118721cee2a0c6eb#166991b1b18188ee2d8441f7118721cee2a0c6eb" dependencies = [ - "jni", + "jni 0.21.1", "robius-android-env", "windows 0.61.3", ] @@ -6747,6 +9570,17 @@ dependencies = [ "memchr 2.7.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rpassword" +version = "7.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2da316a15f47e3d053de9cb2c439650bd8fa4aaeb9365f2e5f27f492ff73c196" +dependencies = [ + "libc", + "rtoolbox", + "windows-sys 0.61.1", +] + [[package]] name = "rqrr" version = "0.10.1" @@ -6778,6 +9612,26 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rsqlite-vfs" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c51c9ae4df8a7fba42103df5c621fa3c37eccf3a3c650879e90fc48b11cc192c" +dependencies = [ + "hashbrown 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 2.0.20", +] + +[[package]] +name = "rtoolbox" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a1efe12a1469752d0e6ff5ebec0b6ef4924cc5c4c71046b0ec730040535819d" +dependencies = [ + "libc", + "windows-sys 0.61.1", +] + [[package]] name = "ruma" version = "0.16.0" @@ -6876,7 +9730,7 @@ version = "0.8.0" source = "git+https://github.com/project-robius/ruma.git?branch=tsp#7a912c8579871e72468ee5a4deecc16615e73099" dependencies = [ "as_variant", - "html5ever", + "html5ever 0.39.0", "ruma-common", "tracing", "wildmatch", @@ -6904,7 +9758,7 @@ dependencies = [ "ruma-identifiers-validation", "serde", "syn 3.0.3", - "toml", + "toml 1.1.2+spec-1.1.0", ] [[package]] @@ -6919,12 +9773,54 @@ dependencies = [ "hashlink 0.12.2", "libsqlite3-sys", "smallvec 1.15.1 (registry+https://github.com/rust-lang/crates.io-index)", + "sqlite-wasm-rs", +] + +[[package]] +name = "rust-embed" +version = "8.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9e7760e252aaba7b09f4be00e36476cf585bdb68a53552ac954cdf504ab4bc9" +dependencies = [ + "rust-embed-impl", + "rust-embed-utils", + "walkdir", +] + +[[package]] +name = "rust-embed-impl" +version = "8.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bcfc4d6f53af43755f7a723e4b6b8794fcce052a178dd8c6c1dadc5f5343097" +dependencies = [ + "mime_guess", + "proc-macro2", + "quote", + "rust-embed-utils", + "syn 2.0.119", + "walkdir", +] + +[[package]] +name = "rust-embed-utils" +version = "8.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ffa149f6aa81b58a5b3011d01a857c4ed12c7a732d2c51947a4c7c692185f0" +dependencies = [ + "sha2 0.11.0", + "walkdir", ] +[[package]] +name = "rustc-demangle" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b74b56ffa8bb2830709a538c2cbcae9aa062db0d2a42563bfb09bdaae44020eb" + [[package]] name = "rustc-hash" version = "1.1.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "rustc-hash" @@ -7009,7 +9905,7 @@ checksum = "1d99feebc72bae7ab76ba994bb5e121b8d83d910ca40b36e0921f53becc41784" dependencies = [ "core-foundation 0.10.1", "core-foundation-sys", - "jni", + "jni 0.21.1", "log", "once_cell 1.21.4", "rustls", @@ -7049,17 +9945,17 @@ checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "rustybuzz" version = "0.18.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "bitflags 2.10.0", "bytemuck 1.25.0", "makepad-error-log", - "smallvec 1.15.1 (git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4)", + "smallvec 1.15.1 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", "ttf-parser 0.24.1", "unicode-bidi-mirroring 0.3.0", "unicode-ccc 0.3.0", "unicode-properties 0.1.4", - "unicode-script 0.5.8 (git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4)", + "unicode-script 0.5.8 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", ] [[package]] @@ -7080,6 +9976,28 @@ dependencies = [ "unicode-script 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rustyline" +version = "15.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ee1e066dc922e513bda599c6ccb5f3bb2b0ea5870a579448f2622993f0a9a2f" +dependencies = [ + "bitflags 2.13.1", + "cfg-if 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "clipboard-win", + "fd-lock", + "home", + "libc", + "log", + "memchr 2.7.6 (registry+https://github.com/rust-lang/crates.io-index)", + "nix 0.29.0", + "radix_trie", + "unicode-segmentation 1.13.3", + "unicode-width", + "utf8parse", + "windows-sys 0.59.0", +] + [[package]] name = "ryu" version = "1.0.20" @@ -7155,12 +10073,26 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9558e172d4e8533736ba97870c4b2cd63f84b382a3d6eb063da41b91cce17289" dependencies = [ + "chrono", "dyn-clone", "ref-cast", + "schemars_derive", "serde", "serde_json", ] +[[package]] +name = "schemars_derive" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "301858a4023d78debd2353c7426dc486001bddc91ae31a76fb1f55132f7e2633" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn 2.0.119", +] + [[package]] name = "scoped-tls" version = "1.0.1" @@ -7170,7 +10102,7 @@ checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" [[package]] name = "scoped-tls" version = "1.0.1" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "scopeguard" @@ -7178,10 +10110,30 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "scroll" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1257cd4248b4132760d6524d6dda4e053bc648c9070b960929bf50cfb1e7add" +dependencies = [ + "scroll_derive", +] + +[[package]] +name = "scroll_derive" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1a36a382ed65dbcc0ab47fd5e9a94112417ccd34560a392ef3b7b0f0ec39148" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] + [[package]] name = "sdfer" version = "0.2.1" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "sealed" @@ -7207,6 +10159,25 @@ dependencies = [ "zeroize", ] +[[package]] +name = "seccompiler" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4ae55de56877481d112a559bbc12667635fdaf5e005712fd4e2b2fa50ffc884" +dependencies = [ + "libc", +] + +[[package]] +name = "secrecy" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e891af845473308773346dc847b2c23ee78fe442e0472ac50e22a18a93d3ae5a" +dependencies = [ + "serde", + "zeroize", +] + [[package]] name = "security-framework" version = "2.11.1" @@ -7331,6 +10302,17 @@ dependencies = [ "syn 3.0.3", ] +[[package]] +name = "serde_derive_internals" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + [[package]] name = "serde_html_form" version = "0.4.1" @@ -7350,6 +10332,7 @@ version = "1.0.151" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14" dependencies = [ + "indexmap 2.14.2", "itoa", "memchr 2.7.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde", @@ -7390,6 +10373,15 @@ dependencies = [ "syn 3.0.3", ] +[[package]] +name = "serde_spanned" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +dependencies = [ + "serde", +] + [[package]] name = "serde_spanned" version = "1.1.1" @@ -7413,19 +10405,20 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.14.1" +version = "3.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c522100790450cf78eeac1507263d0a350d4d5b30df0c8e1fe051a10c22b376e" +checksum = "935177bb8c0cd8ca1a4e6d1a2ac8988bea69cab4f9d3a31311e012ad27868ea4" dependencies = [ - "base64 0.22.1", + "base64 0.23.1", + "bs58", "chrono", "hex", "indexmap 1.9.3", "indexmap 2.14.2", + "jiff", "schemars 0.9.0", "schemars 1.1.0", - "serde", - "serde_derive", + "serde_core", "serde_json", "serde_with_macros", "time", @@ -7433,14 +10426,29 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.14.1" +version = "3.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327ada00f7d64abaac1e55a6911e90cf665aa051b9a561c7006c157f4633135e" +checksum = "1d607aa01a3cb0ad757d6fd216136910db3c97b102fe686585689615a02dbcdc" dependencies = [ - "darling 0.21.3", + "darling 0.24.1", "proc-macro2", "quote", - "syn 2.0.119", + "syn 3.0.3", +] + +[[package]] +name = "serde_yml" +version = "0.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59e2dd588bf1597a252c3b920e0143eb99b0f76e4e082f4c92ce34fbc9e71ddd" +dependencies = [ + "indexmap 2.14.2", + "itoa", + "libyml", + "memchr 2.7.6 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu", + "serde", + "version_check", ] [[package]] @@ -7474,6 +10482,16 @@ dependencies = [ "digest 0.10.7", ] +[[package]] +name = "sha1-checked" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89f599ac0c323ebb1c6082821a54962b839832b03984598375bff3975b804423" +dependencies = [ + "digest 0.10.7", + "sha1", +] + [[package]] name = "sha2" version = "0.10.9" @@ -7505,6 +10523,12 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "shell-words" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc6fe69c597f9c37bfeeeeeb33da3530379845f10be461a66d16d03eca2ded77" + [[package]] name = "shlex" version = "1.3.0" @@ -7542,7 +10566,7 @@ dependencies = [ [[package]] name = "simd-adler32" version = "0.3.9" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "simd-adler32" @@ -7550,6 +10574,40 @@ version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea" +[[package]] +name = "simd_cesu8" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11031e251abf8611c80f460e19dbdeb54a66db918e49c65a7065b46ac7aec520" +dependencies = [ + "rustc_version", + "simdutf8", +] + +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + +[[package]] +name = "similar" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa" + +[[package]] +name = "simple_asn1" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d585997b0ac10be3c5ee635f1bab02d512760d14b7c468801ac8a01d9ae5f1d" +dependencies = [ + "num-bigint", + "num-traits 0.2.19", + "thiserror 2.0.20", + "time", +] + [[package]] name = "simplecss" version = "0.2.2" @@ -7565,6 +10623,12 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" +[[package]] +name = "sketches-ddsketch" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c6f73aeb92d671e0cc4dca167e59b2deb6387c375391bc99ee743f326994a2b" + [[package]] name = "skrifa" version = "0.44.0" @@ -7608,7 +10672,7 @@ dependencies = [ [[package]] name = "smallvec" version = "1.15.1" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "smol_str" @@ -7642,7 +10706,7 @@ dependencies = [ [[package]] name = "spirv" version = "0.3.0+sdk-1.3.268.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "bitflags 2.10.0", ] @@ -7657,6 +10721,18 @@ dependencies = [ "der", ] +[[package]] +name = "sqlite-wasm-rs" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc3efc0da82635d7e1ced0053bbbfa8c7ab9645d0bf36ceb4f7127bb85315d75" +dependencies = [ + "cc", + "js-sys", + "rsqlite-vfs", + "wasm-bindgen", +] + [[package]] name = "sqlx" version = "0.8.6" @@ -7842,6 +10918,19 @@ dependencies = [ "url", ] +[[package]] +name = "sse-stream" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c25ac7aff0abd1dbc474536e40416e1102c7dd9bfba0b9861c6d357f835dcfb4" +dependencies = [ + "bytes", + "futures-util", + "http-body", + "http-body-util", + "pin-project-lite", +] + [[package]] name = "stable_deref_trait" version = "1.2.0" @@ -7854,6 +10943,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +[[package]] +name = "streaming-iterator" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b2231b7c3057d5e4ad0156fb3dc807d900806020c5ffa3ee6ff2c8c76fb8520" + [[package]] name = "strict-num" version = "0.1.1" @@ -7863,6 +10958,19 @@ dependencies = [ "float-cmp", ] +[[package]] +name = "string_cache" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf776ba3fa74f83bf4b63c3dcbbf82173db2632ed8452cb2d891d33f459de70f" +dependencies = [ + "new_debug_unreachable", + "parking_lot", + "phf_shared 0.11.3", + "precomputed-hash", + "serde", +] + [[package]] name = "string_cache" version = "0.9.0" @@ -7876,6 +10984,18 @@ dependencies = [ "serde", ] +[[package]] +name = "string_cache_codegen" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c711928715f1fe0fe509c53b43e993a9a557babc2d0a3567d0a3006f1ac931a0" +dependencies = [ + "phf_generator 0.11.3", + "phf_shared 0.11.3", + "proc-macro2", + "quote", +] + [[package]] name = "string_cache_codegen" version = "0.6.1" @@ -7910,6 +11030,9 @@ name = "strum" version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9628de9b8791db39ceda2b119bbe13134770b56c138ec1d3af810d045c04f9bd" +dependencies = [ + "strum_macros", +] [[package]] name = "strum_macros" @@ -7937,7 +11060,7 @@ dependencies = [ "cssparser", "derive_more 2.0.1", "encoding_rs", - "euclid", + "euclid 0.22.14", "icu_segmenter", "indexmap 2.14.2", "itertools 0.14.0", @@ -7961,7 +11084,7 @@ dependencies = [ "smallbitvec", "smallvec 1.15.1 (registry+https://github.com/rust-lang/crates.io-index)", "static_assertions", - "string_cache", + "string_cache 0.9.0", "strum", "strum_macros", "stylo_atoms", @@ -7977,7 +11100,7 @@ dependencies = [ "url", "void", "walkdir", - "web_atoms", + "web_atoms 0.2.3", ] [[package]] @@ -7986,8 +11109,8 @@ version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "706e5fd9b66b8c1aa1e73e2acecdbec7b274d5bba7fe8946139696184e54978b" dependencies = [ - "string_cache", - "string_cache_codegen", + "string_cache 0.9.0", + "string_cache_codegen 0.6.1", ] [[package]] @@ -8021,12 +11144,12 @@ checksum = "29c7312cba289bd0015f64397a25af604ac551426b503dde9d64a0deed59751e" dependencies = [ "app_units", "cssparser", - "euclid", + "euclid 0.22.14", "selectors", "servo_arc", "smallbitvec", "smallvec 1.15.1 (registry+https://github.com/rust-lang/crates.io-index)", - "string_cache", + "string_cache 0.9.0", "thin-vec", "void", ] @@ -8037,7 +11160,7 @@ version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75e76005daba1feda388038f018ecbcdcddaabac66b02d1a10ad3379fdd1455d" dependencies = [ - "toml", + "toml 1.1.2+spec-1.1.0", ] [[package]] @@ -8060,7 +11183,7 @@ dependencies = [ "app_units", "bitflags 2.13.1", "cssparser", - "euclid", + "euclid 0.22.14", "malloc_size_of_derive", "selectors", "serde", @@ -8089,6 +11212,12 @@ dependencies = [ "siphasher", ] +[[package]] +name = "symlink" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7973cce6668464ea31f176d85b13c7ab3bba2cb3b77a2ed26abd7801688010a" + [[package]] name = "syn" version = "1.0.109" @@ -8171,6 +11300,33 @@ dependencies = [ "walkdir", ] +[[package]] +name = "sysctl" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01198a2debb237c62b6826ec7081082d951f46dbb64b0e8c7649a452230d1dfc" +dependencies = [ + "bitflags 2.13.1", + "byteorder 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "enum-as-inner", + "libc", + "thiserror 1.0.69", + "walkdir", +] + +[[package]] +name = "sysinfo" +version = "0.34.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4b93974b3d3aeaa036504b8eefd4c039dced109171c1ae973f1dc63b2c7e4b2" +dependencies = [ + "libc", + "memchr 2.7.6 (registry+https://github.com/rust-lang/crates.io-index)", + "ntapi", + "objc2-core-foundation", + "windows 0.56.0", +] + [[package]] name = "system-configuration" version = "0.6.1" @@ -8202,6 +11358,17 @@ dependencies = [ "smallvec 1.15.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "tar" +version = "0.4.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f6221d9a6003c78398e3b239969f352578258df48c8eb051caadae0015bc840" +dependencies = [ + "filetime", + "libc", + "xattr", +] + [[package]] name = "tempfile" version = "3.27.0" @@ -8215,6 +11382,17 @@ dependencies = [ "windows-sys 0.61.1", ] +[[package]] +name = "tendril" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0" +dependencies = [ + "futf", + "mac", + "utf-8", +] + [[package]] name = "tendril" version = "0.5.0" @@ -8243,7 +11421,7 @@ dependencies = [ [[package]] name = "thiserror" version = "2.0.18" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "thiserror-impl 2.0.18", ] @@ -8271,7 +11449,7 @@ dependencies = [ [[package]] name = "thiserror-impl" version = "2.0.18" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "makepad-micro-proc-macro", ] @@ -8366,6 +11544,18 @@ dependencies = [ "strict-num", ] +[[package]] +name = "tiny_http" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "389915df6413a2e74fb181895f933386023c71110878cd0825588928e64cdc82" +dependencies = [ + "ascii", + "chunked_transfer", + "httpdate", + "log", +] + [[package]] name = "tinystr" version = "0.8.4" @@ -8402,7 +11592,7 @@ dependencies = [ "servo_arc", "smallbitvec", "smallvec 1.15.1 (registry+https://github.com/rust-lang/crates.io-index)", - "string_cache", + "string_cache 0.9.0", "thin-vec", ] @@ -8428,6 +11618,7 @@ dependencies = [ "bytes", "libc", "mio", + "parking_lot", "pin-project-lite", "signal-hook-registry", "socket2", @@ -8478,6 +11669,22 @@ dependencies = [ "tokio-util", ] +[[package]] +name = "tokio-tungstenite" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edc5f74e248dc973e0dbb7b74c7e0d6fcc301c694ff50049504004ef4d0cdcd9" +dependencies = [ + "futures-util", + "log", + "rustls", + "rustls-native-certs", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tungstenite 0.24.0", +] + [[package]] name = "tokio-tungstenite" version = "0.26.2" @@ -8491,7 +11698,19 @@ dependencies = [ "rustls-pki-types", "tokio", "tokio-rustls", - "tungstenite", + "tungstenite 0.26.2", +] + +[[package]] +name = "tokio-tungstenite" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f72a05e828585856dacd553fba484c242c46e391fb0e58917c942ee9202915c" +dependencies = [ + "futures-util", + "log", + "tokio", + "tungstenite 0.29.0", ] [[package]] @@ -8508,6 +11727,18 @@ dependencies = [ "tokio", ] +[[package]] +name = "toml" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" +dependencies = [ + "serde", + "serde_spanned 0.6.9", + "toml_datetime 0.6.11", + "toml_edit 0.22.27", +] + [[package]] name = "toml" version = "1.1.2+spec-1.1.0" @@ -8516,13 +11747,22 @@ checksum = "81f3d15e84cbcd896376e6730314d59fb5a87f31e4b038454184435cd57defee" dependencies = [ "indexmap 2.14.2", "serde_core", - "serde_spanned", + "serde_spanned 1.1.1", "toml_datetime 1.1.1+spec-1.1.0", "toml_parser", "toml_writer", "winnow 1.0.1", ] +[[package]] +name = "toml_datetime" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" +dependencies = [ + "serde", +] + [[package]] name = "toml_datetime" version = "0.7.3" @@ -8541,6 +11781,20 @@ dependencies = [ "serde_core", ] +[[package]] +name = "toml_edit" +version = "0.22.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" +dependencies = [ + "indexmap 2.14.2", + "serde", + "serde_spanned 0.6.9", + "toml_datetime 0.6.11", + "toml_write", + "winnow 0.7.15", +] + [[package]] name = "toml_edit" version = "0.23.4" @@ -8550,7 +11804,7 @@ dependencies = [ "indexmap 2.14.2", "toml_datetime 0.7.3", "toml_parser", - "winnow 0.7.13", + "winnow 0.7.15", ] [[package]] @@ -8562,6 +11816,12 @@ dependencies = [ "winnow 1.0.1", ] +[[package]] +name = "toml_write" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" + [[package]] name = "toml_writer" version = "1.1.1+spec-1.1.0" @@ -8605,6 +11865,7 @@ dependencies = [ "tower", "tower-layer", "tower-service", + "tracing", ] [[package]] @@ -8631,6 +11892,19 @@ dependencies = [ "tracing-core", ] +[[package]] +name = "tracing-appender" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "050686193eb999b4bb3bc2acfa891a13da00f79734704c4b8b4ef1a10b368a3c" +dependencies = [ + "crossbeam-channel", + "symlink", + "thiserror 2.0.20", + "time", + "tracing-subscriber", +] + [[package]] name = "tracing-attributes" version = "0.1.31" @@ -8652,6 +11926,16 @@ dependencies = [ "valuable", ] +[[package]] +name = "tracing-error" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b1581020d7a273442f5b45074a6a57d5757ad0a47dac0e9f0bd57b81936f3db" +dependencies = [ + "tracing", + "tracing-subscriber", +] + [[package]] name = "tracing-log" version = "0.2.0" @@ -8664,21 +11948,93 @@ dependencies = [ ] [[package]] -name = "tracing-subscriber" -version = "0.3.23" +name = "tracing-serde" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "704b1aeb7be0d0a84fc9828cae51dab5970fee5088f83d1dd7ee6f6246fc6ff1" +dependencies = [ + "serde", + "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 1.21.4", + "regex-automata", + "serde", + "serde_json", + "sharded-slab", + "smallvec 1.15.1 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", + "tracing-serde", +] + +[[package]] +name = "tree-sitter" +version = "0.24.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5387dffa7ffc7d2dae12b50c6f7aab8ff79d6210147c6613561fc3d474c6f75" +dependencies = [ + "cc", + "regex", + "regex-syntax", + "streaming-iterator", + "tree-sitter-language", +] + +[[package]] +name = "tree-sitter-javascript" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf40bf599e0416c16c125c3cec10ee5ddc7d1bb8b0c60fa5c4de249ad34dc1b1" +dependencies = [ + "cc", + "tree-sitter-language", +] + +[[package]] +name = "tree-sitter-language" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca0d1bf6fdd806e43ae5198f82f527056d359def39e54e67a0f478ac09dac081" + +[[package]] +name = "tree-sitter-python" +version = "0.23.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d065aaa27f3aaceaf60c1f0e0ac09e1cb9eb8ed28e7bcdaa52129cffc7f4b04" +dependencies = [ + "cc", + "tree-sitter-language", +] + +[[package]] +name = "tree-sitter-rust" +version = "0.23.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca8ccb3e3a3495c8a943f6c3fd24c3804c471fd7f4f16087623c7fa4c0068e8a" +dependencies = [ + "cc", + "tree-sitter-language", +] + +[[package]] +name = "tree-sitter-typescript" +version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319" +checksum = "6c5f76ed8d947a75cc446d5fccd8b602ebf0cde64ccf2ffa434d873d7a575eff" dependencies = [ - "matchers", - "nu-ansi-term", - "once_cell 1.21.4", - "regex-automata", - "sharded-slab", - "smallvec 1.15.1 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local", - "tracing", - "tracing-core", - "tracing-log", + "cc", + "tree-sitter-language", ] [[package]] @@ -8721,7 +12077,7 @@ dependencies = [ "thiserror 2.0.20", "tokio", "tokio-rustls", - "tokio-tungstenite", + "tokio-tungstenite 0.26.2", "tokio-util", "tracing", "typenum", @@ -8732,7 +12088,7 @@ dependencies = [ [[package]] name = "ttf-parser" version = "0.24.1" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "ttf-parser" @@ -8743,6 +12099,26 @@ dependencies = [ "core_maths", ] +[[package]] +name = "tungstenite" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18e5b8366ee7a95b16d32197d0b2604b43a0be89dc5fac9f8e96ccafbaedda8a" +dependencies = [ + "byteorder 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes", + "data-encoding", + "http", + "httparse", + "log", + "rand 0.8.5", + "rustls", + "rustls-pki-types", + "sha1", + "thiserror 1.0.69", + "utf-8", +] + [[package]] name = "tungstenite" version = "0.26.2" @@ -8762,6 +12138,48 @@ dependencies = [ "utf-8", ] +[[package]] +name = "tungstenite" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8628dcc84e5a09eb3d8423d6cb682965dea9133204e8fb3efee74c2a0c259442" +dependencies = [ + "bytes", + "data-encoding", + "http", + "httparse", + "log", + "rand 0.9.2", + "sha1", + "thiserror 2.0.20", + "utf-8", +] + +[[package]] +name = "tungstenite" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c01152af293afb9c7c2a57e4b559c5620b421f6d133261c60dd2d0cdb38e6b8" +dependencies = [ + "bytes", + "data-encoding", + "http", + "httparse", + "log", + "rand 0.9.2", + "sha1", + "thiserror 2.0.20", +] + +[[package]] +name = "type1-encoding-parser" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa10c302f5a53b7ad27fd42a3996e23d096ba39b5b8dd6d9e683a05b01bee749" +dependencies = [ + "pom", +] + [[package]] name = "typed-arena" version = "2.0.2" @@ -8825,7 +12243,7 @@ checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" [[package]] name = "unicase" version = "2.9.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "unicode-bidi" @@ -8836,12 +12254,12 @@ checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" [[package]] name = "unicode-bidi" version = "0.3.18" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "unicode-bidi-mirroring" version = "0.3.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "unicode-bidi-mirroring" @@ -8849,10 +12267,16 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5dfa6e8c60bb66d49db113e0125ee8711b7647b5579dc7f5f19c42357ed039fe" +[[package]] +name = "unicode-bom" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7eec5d1121208364f6793f7d2e222bf75a915c19557537745b195b253dd64217" + [[package]] name = "unicode-ccc" version = "0.3.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "unicode-ccc" @@ -8869,12 +12293,12 @@ checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" [[package]] name = "unicode-ident" version = "1.0.22" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "unicode-linebreak" version = "0.1.5" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "unicode-normalization" @@ -8894,7 +12318,7 @@ checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" [[package]] name = "unicode-properties" version = "0.1.4" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "unicode-script" @@ -8905,12 +12329,12 @@ checksum = "383ad40bb927465ec0ce7720e033cb4ca06912855fc35db31b5755d0de75b1ee" [[package]] name = "unicode-script" version = "0.5.8" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "unicode-segmentation" version = "1.12.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "unicode-segmentation" @@ -9284,10 +12708,10 @@ dependencies = [ [[package]] name = "wayland-backend" version = "0.3.12" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "downcast-rs", - "scoped-tls 1.0.1 (git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4)", + "scoped-tls 1.0.1 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", "smallvec 1.15.1 (registry+https://github.com/rust-lang/crates.io-index)", "wayland-sys", ] @@ -9295,7 +12719,7 @@ dependencies = [ [[package]] name = "wayland-client" version = "0.31.12" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "bitflags 2.10.0", "wayland-backend", @@ -9305,7 +12729,7 @@ dependencies = [ [[package]] name = "wayland-egl" version = "0.32.9" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "wayland-backend", "wayland-sys", @@ -9314,7 +12738,7 @@ dependencies = [ [[package]] name = "wayland-protocols" version = "0.32.10" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "bitflags 2.10.0", "wayland-backend", @@ -9324,10 +12748,10 @@ dependencies = [ [[package]] name = "wayland-sys" version = "0.31.8" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "makepad-error-log", - "pkg-config 0.3.32 (git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4)", + "pkg-config 0.3.32 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", ] [[package]] @@ -9351,6 +12775,18 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "web_atoms" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57ffde1dc01240bdf9992e3205668b235e59421fd085e8a317ed98da0178d414" +dependencies = [ + "phf 0.11.3", + "phf_codegen 0.11.3", + "string_cache 0.8.9", + "string_cache_codegen 0.5.4", +] + [[package]] name = "web_atoms" version = "0.2.3" @@ -9359,8 +12795,24 @@ checksum = "57a9779e9f04d2ac1ce317aee707aa2f6b773afba7b931222bff6983843b1576" dependencies = [ "phf 0.13.1", "phf_codegen 0.13.1", - "string_cache", - "string_cache_codegen", + "string_cache 0.9.0", + "string_cache_codegen 0.6.1", +] + +[[package]] +name = "webbrowser" +version = "1.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62c35be770821a214dbc362fc26908c853e776c0004294d0b10b8a6bad582f94" +dependencies = [ + "jni 0.22.4", + "log", + "ndk-context", + "objc2", + "objc2-app-kit", + "objc2-foundation", + "url", + "web-sys", ] [[package]] @@ -9372,6 +12824,15 @@ dependencies = [ "rustls-pki-types", ] +[[package]] +name = "webpki-roots" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dcd9d09a39985f5344844e66b0c530a33843579125f23e21e9f0f220850f22a" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "weezl" version = "0.1.12" @@ -9381,7 +12842,28 @@ checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88" [[package]] name = "weezl" version = "0.1.12" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" + +[[package]] +name = "which" +version = "7.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d643ce3fd3e5b54854602a080f34fb10ab75e0b813ee32d00ca2b44fa74762" +dependencies = [ + "either", + "env_home", + "rustix", + "winsafe", +] + +[[package]] +name = "which" +version = "8.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bae2f2b2b816647a1cab1acc91f5bd20812d53cb344382635ec2181940c8034f" +dependencies = [ + "libc", +] [[package]] name = "whoami" @@ -9403,12 +12885,34 @@ dependencies = [ "safe_arch", ] +[[package]] +name = "widestring" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72069c3113ab32ab29e5584db3c6ec55d416895e60715417b5b883a357c3e471" + [[package]] name = "wildmatch" version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29333c3ea1ba8b17211763463ff24ee84e41c78224c16b001cd907e663a38c68" +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + [[package]] name = "winapi-util" version = "0.1.11" @@ -9418,6 +12922,21 @@ dependencies = [ "windows-sys 0.61.1", ] +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" +dependencies = [ + "windows-targets 0.48.5", +] + [[package]] name = "windows" version = "0.56.0" @@ -9456,11 +12975,11 @@ dependencies = [ [[package]] name = "windows" version = "0.62.2" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ - "windows-collections 0.3.2 (git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4)", - "windows-core 0.62.2 (git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4)", - "windows-future 0.3.2 (git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4)", + "windows-collections 0.3.2 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", + "windows-core 0.62.2 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", + "windows-future 0.3.2 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", ] [[package]] @@ -9484,9 +13003,9 @@ dependencies = [ [[package]] name = "windows-collections" version = "0.3.2" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ - "windows-core 0.62.2 (git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4)", + "windows-core 0.62.2 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", ] [[package]] @@ -9530,11 +13049,11 @@ dependencies = [ [[package]] name = "windows-core" version = "0.62.2" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ - "windows-link 0.2.1 (git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4)", - "windows-result 0.4.1 (git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4)", - "windows-strings 0.5.1 (git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4)", + "windows-link 0.2.1 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", + "windows-result 0.4.1 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", + "windows-strings 0.5.1 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", ] [[package]] @@ -9562,9 +13081,9 @@ dependencies = [ [[package]] name = "windows-future" version = "0.3.2" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ - "windows-core 0.62.2 (git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4)", + "windows-core 0.62.2 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", ] [[package]] @@ -9626,7 +13145,7 @@ checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] name = "windows-link" version = "0.2.1" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "windows-numerics" @@ -9659,6 +13178,17 @@ dependencies = [ "windows-strings 0.4.2", ] +[[package]] +name = "windows-registry" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" +dependencies = [ + "windows-link 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "windows-result 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "windows-strings 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "windows-result" version = "0.1.2" @@ -9689,9 +13219,9 @@ dependencies = [ [[package]] name = "windows-result" version = "0.4.1" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ - "windows-link 0.2.1 (git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4)", + "windows-link 0.2.1 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", ] [[package]] @@ -9715,9 +13245,9 @@ dependencies = [ [[package]] name = "windows-strings" version = "0.5.1" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ - "windows-link 0.2.1 (git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4)", + "windows-link 0.2.1 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", ] [[package]] @@ -9747,6 +13277,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-sys" version = "0.60.2" @@ -10028,9 +13567,18 @@ checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" [[package]] name = "winnow" -version = "0.7.13" +version = "0.6.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e90edd2ac1aa278a5c4599b1d89cf03074b610800f866d4026dc199d7929a28" +dependencies = [ + "memchr 2.7.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winnow" +version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" +checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" dependencies = [ "memchr 2.7.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -10050,10 +13598,16 @@ version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0986a8b1d586b7d3e4fe3d9ea39fb451ae22869dcea4aa109d287a374d866087" dependencies = [ - "toml", + "toml 1.1.2+spec-1.1.0", "version_check", ] +[[package]] +name = "winsafe" +version = "0.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" + [[package]] name = "wit-bindgen" version = "0.46.0" @@ -10106,6 +13660,36 @@ dependencies = [ "zeroize", ] +[[package]] +name = "xattr" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156" +dependencies = [ + "libc", + "rustix", +] + +[[package]] +name = "xml5ever" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee3f1e41afb31a75aef076563b0ad3ecc24f5bd9d12a72b132222664eb76b494" +dependencies = [ + "log", + "markup5ever 0.35.0", +] + +[[package]] +name = "xml5ever" +version = "0.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dc9559429edf0cd3f327cc0afd9d6b36fa8cec6d93107b7fbe64f806b5f2d9" +dependencies = [ + "log", + "markup5ever 0.38.0", +] + [[package]] name = "xml5ever" version = "0.39.0" @@ -10113,7 +13697,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ab627f34ff61b80d756180d556f9c68801d836d271b3b8c094504ceca69d221" dependencies = [ "log", - "markup5ever", + "markup5ever 0.39.0", ] [[package]] @@ -10128,6 +13712,15 @@ version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdd20c5420375476fbd4394763288da7eb0cc0b8c11deed431a91562af7335d3" +[[package]] +name = "xz2" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388c44dc09d76f1536602ead6d325eb532f5c122f17782bd57fb47baeeb767e2" +dependencies = [ + "lzma-sys", +] + [[package]] name = "yeslogic-fontconfig-sys" version = "6.0.1" @@ -10244,7 +13837,7 @@ dependencies = [ [[package]] name = "zerocopy" version = "0.8.39" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "zerocopy-derive" @@ -10333,12 +13926,88 @@ dependencies = [ "syn 3.0.3", ] +[[package]] +name = "zip" +version = "2.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fabe6324e908f85a1c52063ce7aa26b68dcb7eb6dbc83a2d148403c9bc3eba50" +dependencies = [ + "aes 0.8.4", + "arbitrary", + "bzip2", + "constant_time_eq 0.3.1", + "crc32fast", + "crossbeam-utils", + "deflate64", + "displaydoc", + "flate2", + "getrandom 0.3.3", + "hmac 0.12.1", + "indexmap 2.14.2", + "lzma-rs", + "memchr 2.7.6 (registry+https://github.com/rust-lang/crates.io-index)", + "pbkdf2 0.12.2", + "sha1", + "thiserror 2.0.20", + "time", + "xz2", + "zeroize", + "zopfli", + "zstd", +] + +[[package]] +name = "zlib-rs" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b268e58e7c693d7c271f93ffc4ba3b380412554231c85bf61ca7af91042a4112" + [[package]] name = "zmij" version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd8f3f50b848df28f887acb68e41201b5aea6bc8a8dacc00fb40635ff9a72fea" +[[package]] +name = "zopfli" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f05cd8797d63865425ff89b5c4a48804f35ba0ce8d125800027ad6017d2b5249" +dependencies = [ + "bumpalo", + "crc32fast", + "log", + "simd-adler32 0.3.10", +] + +[[package]] +name = "zstd" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "7.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64d80649ab6db9d9f6f9c80a40becd948eda4714a0a5ac8c4d157a32231c7882" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.1.0+zstd.1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ef0a8027ec3ee71300ab3bcbcd0393f434aa72b91ca6d635a39941deae8eea0" +dependencies = [ + "cc", + "pkg-config 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "zune-core" version = "0.5.3" @@ -10394,3 +14063,33 @@ dependencies = [ "syn 3.0.3", "winnow 1.0.1", ] + +[[patch.unused]] +name = "makepad-ai" +version = "1.0.0" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" + +[[patch.unused]] +name = "makepad-aichat" +version = "0.1.0" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" + +[[patch.unused]] +name = "makepad-photos" +version = "0.1.0" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" + +[[patch.unused]] +name = "makepad-sheets" +version = "0.1.0" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" + +[[patch.unused]] +name = "makepad-wm-api" +version = "0.1.0" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" + +[[patch.unused]] +name = "makepad-wm-theme" +version = "0.1.0" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" diff --git a/Cargo.toml b/Cargo.toml index a0a7bdcc..b0f100a2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,10 +15,17 @@ metadata.makepad-auto-version = "zqpv-Yj-K7WNVK2I8h5Okhho46Q=" [dependencies] article-core = { path = "crates/article-core", features = ["l0"] } +rinx-miniapp-core = { path = "crates/miniapp-core" } +uuid = { version = "1", features = ["v4"] } +octos-app-transport = { git = "https://github.com/OctoSense-org/OctoSense-System-Apps.git", rev = "1576bec6a585758e48c3252030cad2a9bf9c80db" } +octoscript-ui-l0 = { git = "https://github.com/OctoSense-org/Octoscript.git", rev = "68f6a9df55692b5d8ef8873a12721e279a3f40d6" } +octoscript-makepad = { git = "https://github.com/OctoSense-org/Octoscript-Makepad.git", rev = "b9034566b0607c5bb8c04134d17139f99989e1d0" } +octoscript-widgets = { git = "https://github.com/OctoSense-org/Octoscript-Makepad.git", rev = "b9034566b0607c5bb8c04134d17139f99989e1d0" } +octosense-app-policy = { git = "https://github.com/OctoSense-org/OctoSense-App-Hub.git", rev = "b0591e2caa0dc5c62927f7b85dbf826a50618a03", features = ["splash"] } article-makepad = { path = "crates/article-makepad" } ## The OctoSense module contract. Only a host build uses it, and the host redirects ## all of makepad to its own copy (OctoSense-org/makepad rinx/octosense-module-windows). -makepad-app-module = { git = "https://github.com/OctoSense-org/makepad", rev = "1d3d383e84a66dbb18a4a860f505430c9d5b20f4", optional = true } +makepad-app-module = { git = "https://github.com/OctoSense-org/makepad", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d", optional = true } makepad-html-renderer = { package = "makepad-html", git = "https://github.com/OctoSense-org/makepad-html", rev = "b16565ae1e56dd7c3a87f00455ae327df599ca3b", optional = true, features = ["makepad"] } # makepad-widgets = { git = "https://github.com/makepad/makepad", branch = "dev", features = ["serde"] } # makepad-code-editor = { git = "https://github.com/makepad/makepad", branch = "dev" } @@ -61,8 +68,8 @@ libc = "0.2" mime = "0.3" mime_guess = "2.0" linkify = "0.10.0" -matrix-sdk-base = { git = "https://github.com/matrix-org/matrix-rust-sdk" } -matrix-sdk = { git = "https://github.com/matrix-org/matrix-rust-sdk", default-features = false, features = [ +matrix-sdk-base = { git = "https://github.com/matrix-org/matrix-rust-sdk", rev = "6892cb217ae4a886571e928c8efcccfbec5490a6" } +matrix-sdk = { git = "https://github.com/matrix-org/matrix-rust-sdk", rev = "6892cb217ae4a886571e928c8efcccfbec5490a6", default-features = false, features = [ "e2e-encryption", "automatic-room-key-forwarding", "markdown", @@ -72,8 +79,8 @@ matrix-sdk = { git = "https://github.com/matrix-org/matrix-rust-sdk", default-fe ## The SDK no longer registers a rustls crypto provider unless we ask for one. "rustls-aws-lc-rs", ] } -matrix-sdk-crypto = { git = "https://github.com/matrix-org/matrix-rust-sdk", default-features = false } -matrix-sdk-ui = { git = "https://github.com/matrix-org/matrix-rust-sdk", default-features = false } +matrix-sdk-crypto = { git = "https://github.com/matrix-org/matrix-rust-sdk", rev = "6892cb217ae4a886571e928c8efcccfbec5490a6", default-features = false } +matrix-sdk-ui = { git = "https://github.com/matrix-org/matrix-rust-sdk", rev = "6892cb217ae4a886571e928c8efcccfbec5490a6", default-features = false } ## Use the same ruma version as what's specified in matrix-sdk's Cargo.toml. ## Enable a few extra features: ## * "compat-optional" feature to allow missing body field in m.room.tombstone event. @@ -428,7 +435,60 @@ too_many_arguments = "allow" uninlined_format_args = "allow" used_underscore_binding = "allow" -# Keep all Makepad widgets on the same compatibility revision as the renderer. +# Pin one Makepad and Octoscript runtime across Rinx and its transitive kits. +# The www alias allows Cargo patches to redirect older revisions of the same +# repository. OctoSense shells replace these with their prepared runtime source. + +[patch."https://github.com/OctoSense-org/makepad.git"] +makepad-script = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } +makepad-widgets = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } +makepad-code-editor = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } +makepad-app-module = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } +makepad-ai = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } +makepad-studio-protocol = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } +makepad-network = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } +makepad-wm-api = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } +makepad-ai-services = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } +makepad-strict-json = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } +makepad-wm-theme = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } +makepad-sheets = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } +makepad-photos = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } +makepad-aichat = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } +makepad-markdown = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } +makepad-markdown-widgets = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } + +[patch."https://github.com/OctoSense-org/makepad"] +makepad-script = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } +makepad-widgets = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } +makepad-code-editor = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } +makepad-app-module = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } +makepad-ai = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } +makepad-studio-protocol = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } +makepad-network = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } +makepad-wm-api = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } +makepad-ai-services = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } +makepad-strict-json = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } +makepad-wm-theme = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } +makepad-sheets = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } +makepad-photos = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } +makepad-aichat = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } +makepad-markdown = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } +makepad-markdown-widgets = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } + [patch."https://github.com/kevinaboos/makepad"] -makepad-widgets = { git = "https://github.com/OctoSense-org/makepad", rev = "1d3d383e84a66dbb18a4a860f505430c9d5b20f4" } -makepad-code-editor = { git = "https://github.com/OctoSense-org/makepad", rev = "1d3d383e84a66dbb18a4a860f505430c9d5b20f4" } +makepad-widgets = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } +makepad-code-editor = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } + +[patch."https://github.com/ZhangHanDong/makepad.git"] +makepad-widgets = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } + +[patch."https://github.com/OctoSense-org/Octoscript.git"] +octoscript-ui-l0 = { git = "https://www.github.com/OctoSense-org/Octoscript.git", rev = "68f6a9df55692b5d8ef8873a12721e279a3f40d6" } + +[patch."https://github.com/OctoSense-org/Octoscript"] +octoscript-ui-l0 = { git = "https://www.github.com/OctoSense-org/Octoscript.git", rev = "68f6a9df55692b5d8ef8873a12721e279a3f40d6" } + +[patch."https://github.com/OctoSense-org/Octoscript-Makepad.git"] +octoscript-makepad = { git = "https://www.github.com/OctoSense-org/Octoscript-Makepad.git", rev = "b9034566b0607c5bb8c04134d17139f99989e1d0" } +octoscript-widgets = { git = "https://www.github.com/OctoSense-org/Octoscript-Makepad.git", rev = "b9034566b0607c5bb8c04134d17139f99989e1d0" } +octoscript-node = { git = "https://www.github.com/OctoSense-org/Octoscript-Makepad.git", rev = "b9034566b0607c5bb8c04134d17139f99989e1d0" } diff --git a/crates/article-core/Cargo.toml b/crates/article-core/Cargo.toml index 1df510a0..74794610 100644 --- a/crates/article-core/Cargo.toml +++ b/crates/article-core/Cargo.toml @@ -12,7 +12,7 @@ default = [] l0 = ["dep:octoscript-ui-l0"] [dependencies] -makepad-markdown = { git = "https://github.com/OctoSense-org/makepad", rev = "1d3d383e84a66dbb18a4a860f505430c9d5b20f4", features = ["editormd"] } +makepad-markdown = { git = "https://github.com/OctoSense-org/makepad", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d", features = ["editormd"] } serde = { version = "1", features = ["derive"] } serde_json = "1" rand = "0.8.5" diff --git a/crates/article-makepad/Cargo.toml b/crates/article-makepad/Cargo.toml index 7203f2fa..5e78ce94 100644 --- a/crates/article-makepad/Cargo.toml +++ b/crates/article-makepad/Cargo.toml @@ -8,7 +8,7 @@ description = "Reusable native Makepad article editing and viewing widgets" [workspace] [dependencies] -makepad-markdown-widgets = { git = "https://github.com/OctoSense-org/makepad", rev = "1d3d383e84a66dbb18a4a860f505430c9d5b20f4", features = ["full", "editormd"] } +makepad-markdown-widgets = { git = "https://github.com/OctoSense-org/makepad", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d", features = ["full", "editormd"] } article-core = { path = "../article-core" } makepad-widgets = { git = "https://github.com/kevinaboos/makepad", branch = "button-grab-key-focus", features = ["serde"] } unicode-segmentation = "1.11.0" @@ -16,4 +16,4 @@ libc = "0.2" # Keep all Makepad widgets on the same compatibility revision as the renderer. [patch."https://github.com/kevinaboos/makepad"] -makepad-widgets = { git = "https://github.com/OctoSense-org/makepad", rev = "1d3d383e84a66dbb18a4a860f505430c9d5b20f4" } +makepad-widgets = { git = "https://github.com/OctoSense-org/makepad", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } diff --git a/crates/miniapp-core/Cargo.lock b/crates/miniapp-core/Cargo.lock new file mode 100644 index 00000000..d2e81456 --- /dev/null +++ b/crates/miniapp-core/Cargo.lock @@ -0,0 +1,107 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "memchr" +version = "2.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" + +[[package]] +name = "proc-macro2" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rinx-miniapp-core" +version = "0.1.0" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "serde" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.151" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "syn" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8593e8e72159ed2257d083c7a454a85cbf854f37a0966d8d483aff8c8a3ebcee" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d245f478577f809a851594d02313b640fb437e0bb33866753cff937863096954" + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/crates/miniapp-core/Cargo.toml b/crates/miniapp-core/Cargo.toml new file mode 100644 index 00000000..e8c70cd5 --- /dev/null +++ b/crates/miniapp-core/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "rinx-miniapp-core" +version = "0.1.0" +edition = "2024" +license = "Apache-2.0 AND MIT" +description = "Host-independent mini-app identity, service grants and A2App Matrix contracts" + +[workspace] + +[dependencies] +serde = { version = "1", features = ["derive"] } +serde_json = "1" + diff --git a/crates/miniapp-core/LICENSE-MIT b/crates/miniapp-core/LICENSE-MIT new file mode 100644 index 00000000..7f77de13 --- /dev/null +++ b/crates/miniapp-core/LICENSE-MIT @@ -0,0 +1,9 @@ +The MIT License (MIT) + +Copyright (c) 2023-2026 Project Robius Developers + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/crates/miniapp-core/src/lib.rs b/crates/miniapp-core/src/lib.rs new file mode 100644 index 00000000..7b7d1e92 --- /dev/null +++ b/crates/miniapp-core/src/lib.rs @@ -0,0 +1,226 @@ +//! Portable contracts shared by standalone and embedded mini-app hosts. +pub mod matrix; + +use serde_json::Value; +use std::{ + collections::BTreeSet, + sync::{ + Arc, + atomic::{AtomicBool, AtomicU64, Ordering}, + }, + time::Instant, +}; + +pub const MAX_REQUEST_BYTES: usize = 256 * 1024; +pub const MAX_REPLY_BYTES: usize = 2 * 1024 * 1024; + +/// Identity is assigned by the embedding host, never deserialized from script arguments. +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct InstanceId { + pub app: String, + pub account: String, + pub room: Option, + pub generation: u64, +} + +/// Revocation is shared with asynchronous work, so closing an instance also +/// invalidates already queued requests and replies. +#[derive(Clone, Debug)] +pub struct Lease { + identity: InstanceId, + services: BTreeSet, + rooms: BTreeSet, + expires: Instant, + alive: Arc, + authority: Arc, + epoch: u64, +} + +#[derive(Clone, Debug, Default)] +pub struct SessionAuthority(Arc); +impl SessionAuthority { + pub fn invalidate(&self) { + self.0.fetch_add(1, Ordering::AcqRel); + } + pub fn issue( + &self, + identity: InstanceId, + services: BTreeSet, + rooms: BTreeSet, + expires: Instant, + ) -> Lease { + Lease { + identity, + services, + rooms, + expires, + alive: Arc::new(AtomicBool::new(true)), + authority: self.0.clone(), + epoch: self.0.load(Ordering::Acquire), + } + } +} + +impl Lease { + /// Called only after the host has intersected requested and approved grants. + pub fn new( + identity: InstanceId, + services: BTreeSet, + rooms: BTreeSet, + expires: Instant, + ) -> Self { + SessionAuthority::default().issue(identity, services, rooms, expires) + } + pub fn identity(&self) -> &InstanceId { + &self.identity + } + pub fn services(&self) -> &BTreeSet { + &self.services + } + pub fn revoke(&self) { + self.alive.store(false, Ordering::Release); + } + pub fn check(&self, account: &str) -> Result<(), String> { + if !self.alive.load(Ordering::Acquire) + || Instant::now() >= self.expires + || self.authority.load(Ordering::Acquire) != self.epoch + { + return Err("Mini-app authorization expired".into()); + } + if account != self.identity.account { + return Err("Mini-app account changed".into()); + } + Ok(()) + } + pub fn authorize( + &self, + account: &str, + service: &str, + room: Option<&str>, + ) -> Result<(), String> { + self.check(account)?; + if !self.services.contains(service) { + return Err(format!("Mini app was not granted {service}")); + } + if let Some(room) = room { + if !self.rooms.contains(room) { + return Err("Mini app was not granted access to this room".into()); + } + } + Ok(()) + } + pub fn permits_room(&self, room: &str) -> bool { + self.rooms.contains(room) + } +} + +pub fn parse_arguments(json: &str) -> Result { + if json.len() > MAX_REQUEST_BYTES { + return Err("Mini-app request is too large".into()); + } + let value: Value = + serde_json::from_str(json).map_err(|e| format!("Invalid service arguments: {e}"))?; + if !value.is_object() { + return Err("Service arguments must be an object".into()); + } + Ok(value) +} + +pub fn bounded_reply(value: Value) -> Result { + if serde_json::to_vec(&value).map_err(|e| e.to_string())?.len() > MAX_REPLY_BYTES { + return Err("Mini-app response is too large".into()); + } + Ok(value) +} + +/// One asynchronous response or stream item. A provider must finish a request +/// exactly once; dropping its receiver cancels delivery to a departed app. +#[derive(Debug)] +pub enum ServiceEvent { + Data(Value), + Complete(Result), +} + +/// The Octos connection is supplied by the host. It carries no Matrix tokens +/// and does not own or spawn a kernel merely because a mini app is opened. +pub trait OctosProvider: Send + Sync { + fn request( + &self, + lease: Lease, + service: &str, + args: Value, + reply: std::sync::mpsc::SyncSender, + ) -> Result<(), String>; + /// Called by native host approval UI, never by script service arguments. + fn decide( + &self, + lease: Lease, + approval: &str, + approve: bool, + reply: std::sync::mpsc::SyncSender, + ) -> Result<(), String>; + fn close(&self, identity: &InstanceId); +} + +#[cfg(test)] +mod tests { + use super::*; + use std::time::Duration; + fn lease() -> Lease { + Lease::new( + InstanceId { + app: "test".into(), + account: "@alice:example.org".into(), + room: Some("!allowed:example.org".into()), + generation: 7, + }, + ["matrix.read_messages".into()].into(), + ["!allowed:example.org".into()].into(), + Instant::now() + Duration::from_secs(60), + ) + } + #[test] + fn queued_work_observes_revocation_and_account_changes() { + let original = lease(); + let queued = original.clone(); + assert!(queued.check("@bob:example.org").is_err()); + assert!(queued.check("@alice:example.org").is_ok()); + original.revoke(); + assert!(queued.check("@alice:example.org").is_err()); + } + #[test] + fn read_scope_cannot_be_used_to_publish_or_read_another_room() { + let lease = lease(); + let account = "@alice:example.org"; + assert!( + lease + .authorize( + account, + "matrix.read_messages", + Some("!allowed:example.org") + ) + .is_ok() + ); + assert!( + lease + .authorize(account, "matrix.send_message", Some("!allowed:example.org")) + .is_err() + ); + assert!( + lease + .authorize(account, "matrix.read_messages", Some("!other:example.org")) + .is_err() + ); + assert!(lease.authorize(account, "octos.turn.start", None).is_err()); + } + #[test] + fn script_arguments_cannot_supply_host_identity() { + assert!(parse_arguments("[]").is_err()); + let lease = lease(); + let _forged = parse_arguments( + r#"{"account":"@alice:example.org","room":"!allowed:example.org","generation":7}"#, + ) + .unwrap(); + assert!(lease.check("@bob:example.org").is_err()); + } +} diff --git a/crates/miniapp-core/src/matrix.rs b/crates/miniapp-core/src/matrix.rs new file mode 100644 index 00000000..e914fe95 --- /dev/null +++ b/crates/miniapp-core/src/matrix.rs @@ -0,0 +1,757 @@ +// SPDX-License-Identifier: MIT +// Adapted from project-robius/robrix a2app/core/src/services/matrix.rs +// Source revision: d4d39612fdee574a0f6a33480a19868f1ec85644 +//! The `matrix.*` services: parsing and pricing live here (SDK-free); the +//! host runs the parsed [`MatrixServiceCall`] against the SDK and answers. +//! +//! Sections are per domain so the room, rooms, account and send services +//! can grow independently. A new service needs: its wire id in +//! [`is_service`], an arm in [`parse`], a variant here, and a price in +//! [`cost`]. + +/// A matrix.* service call, parsed and validated by the broker. +pub enum MatrixServiceCall { + /// `{room_id, room_name, topic, member_count}` for the attached room. + RoomInfo, + /// The latest `limit` text messages, oldest first (limit already 1..=30). + ReadMessages { limit: u32 }, + /// Send a plain text message to the attached room as the user. + SendMessage { body: String }, + /// `{user_id, display_name}` — the user's own identity. + Profile, + /// `{count, members: [{name, user_id, power}]}` for the attached room. + Members { limit: u32 }, + /// `{pinned: [{sender, body}]}` — the room's pinned messages. + PinnedEvents, + /// `{threads: [{sender, body}]}` — thread roots, newest first. + Threads { limit: u32 }, + /// Every joined room, with name, kind and encryption flag. + RoomsList, + /// Text search over messages; `scope` says which rooms. + Search { query: String, scope: SearchScope, limit: u32, server: bool }, + + // --- room --- + /// `{root, replies: [message]}` for one thread, oldest first. + ThreadReplies { event_id: String, limit: u32 }, + /// One page of text messages before `before`, or before the recent window. + OlderMessages { before: Option, limit: u32 }, + /// One event by id, with its reactions and edit state. + Event { event_id: String }, + /// The latest read position of one member, or of every joined member. + ReadReceipts { user_id: Option }, + /// `{unread, mentions, marked_unread}` for the attached room. + Unread, + /// The user's power level here and what it lets them do. + PowerLevels, + /// A matrix.to (default) or matrix: link to the room or one of its events. + Permalink { event_id: Option, use_matrix_scheme: bool }, + /// Where an upgraded (tombstoned) room continued. + Successor, + + // --- rooms --- + /// Joined and invited rooms whose name or alias contains `query`. + RoomsSearch { query: String, limit: u32 }, + /// Pending invites, with who sent each. + Invites, + /// Public details of any room by id or alias; hits the homeserver. + RoomPreview { room: String, via: Vec }, + /// The `RoomInfo` shape for any joined room. + RoomsInfo { room_id: String }, + /// The `ReadMessages` shape for any joined room (limit already 1..=30). + RoomsMessages { room_id: String, limit: u32 }, + + // --- spaces --- + /// Every joined space. + Spaces, + /// One joined space's details. + SpaceInfo { space_id: String }, + /// A space's direct child rooms and subspaces. + SpaceRooms { space_id: String }, + + // --- account --- + /// Any user's public profile, plus whether the user ignores them. + UserProfile { user_id: String }, + /// The existing DM room with a user, if any; never creates one. + DmFind { user_id: String }, + /// This device's id, name and verification state. + Device, + /// User id, homeserver and account-management URL. + AccountInfo, + /// The account's ignore list. + IgnoredUsers, + + // --- send --- + /// Reply to `event_id`, or post into the thread rooted there when + /// `in_thread`; answers `{event_id}` of the sent event. + Reply { event_id: String, body: String, in_thread: bool }, + /// Toggle the user's reaction `key` on an event; answers `{added}`. + React { event_id: String, key: String }, + /// Show or hide the user as typing. + Typing { typing: bool }, + /// A read receipt up to `event_id`, or fully read when absent. + ReadReceipt { event_id: Option }, + /// Pin or unpin an event. + Pin { event_id: String, pinned: bool }, + /// Turn one of the attached room's own flags on or off. + RoomFlag { flag: RoomFlag, on: bool }, + /// Plain text to any joined room, `room_id` as given. + RoomsSend { room_id: String, body: String }, + + // --- membership --- + /// Invite `user_id` to the attached room. + Invite { user_id: String }, + /// Join a room by id or alias, knocking when it is invite-only. + Join { room: String, via: Vec }, + /// Accept or decline a pending invite. + InviteRespond { room_id: String, accept: bool }, + /// The DM with `user_id`, created when there is none. + DmOpen { user_id: String }, +} + +/// Which rooms a `matrix.search_*` call covers. +pub enum SearchScope { + Attached, + AllJoined, + /// Room ids as given; the host validates them. + Rooms(Vec), +} + +/// The per-room flags `matrix.favorite`, `matrix.low_priority` and +/// `matrix.mark_unread` set. +#[derive(Debug, Clone, Copy)] +pub enum RoomFlag { + Favorite, + LowPriority, + Unread, +} + +/// Every wire id the broker routes here. +pub fn is_service(service: &str) -> bool { + service.starts_with("matrix.") +} + +/// Services that work without an attached room. +fn room_free(service: &str) -> bool { + matches!(service, + "matrix.profile" | "matrix.rooms_list" | "matrix.search_rooms" + | "matrix.rooms_search" | "matrix.invites" | "matrix.room_preview" + | "matrix.rooms_info" | "matrix.rooms_messages" + | "matrix.spaces" | "matrix.space_info" | "matrix.space_rooms" + | "matrix.user_profile" | "matrix.dm_find" | "matrix.device" + | "matrix.account_info" | "matrix.ignored_users" + + | "matrix.rooms_send" | "matrix.join" | "matrix.invite_respond" | "matrix.dm_open" + + ) +} + +/// A Matrix id argument, checked only for its sigil; the host parses it. +fn id_arg(service: &str, args: &serde_json::Value, key: &str, sigil: char) -> Result { + let id = args[key].as_str().map(str::trim).unwrap_or_default(); + if !id.starts_with(sigil) { + return Err(format!("{service} needs {{{key}}}")); + } + Ok(id.to_string()) +} + +/// A required string argument, trimmed and non-empty. +fn required_str(service: &str, args: &serde_json::Value, key: &str) -> Result { + match args[key].as_str().map(str::trim) { + Some(s) if !s.is_empty() => Ok(s.to_string()), + _ => Err(format!("{service} needs {{{key}}}")), + } +} + +fn required_bool(service: &str, args: &serde_json::Value, key: &str) -> Result { + args[key].as_bool().ok_or_else(|| format!("{service} needs {{{key}: bool}}")) +} + +/// A message body: `required_str` plus the cap every text send shares. +fn text_body(service: &str, args: &serde_json::Value) -> Result { + let body = required_str(service, args, "body")?; + if body.chars().count() > 4096 { + return Err("message is too long (4096 characters max)".into()); + } + Ok(body)} + +/// Validates and clamps a call's arguments. Runs AFTER the permission gate, +/// so a first-use prompt still reads sensibly before an argument error. +pub fn parse(service: &str, args: &serde_json::Value, has_room: bool) -> Result { + if !room_free(service) && !has_room { + return Err("this mini-app is not attached to a room".into()); + } + Ok(match service { + "matrix.room_info" => MatrixServiceCall::RoomInfo, + "matrix.profile" => MatrixServiceCall::Profile, + "matrix.rooms_list" => MatrixServiceCall::RoomsList, + "matrix.search_room" | "matrix.search_rooms" => { + let query = args["query"].as_str().map(str::trim).unwrap_or_default(); + if query.is_empty() { + return Err(format!("{service} needs {{query}}")); + } + let scope = if service == "matrix.search_room" { + SearchScope::Attached + } else { + match args["room_ids"].as_array() { + Some(ids) => SearchScope::Rooms( + ids.iter().filter_map(|v| v.as_str().map(str::to_string)).collect(), + ), + None => SearchScope::AllJoined, + } + }; + MatrixServiceCall::Search { + query: query.to_string(), + scope, + limit: args["limit"].as_u64().unwrap_or(25) as u32, + server: args["server"].as_bool().unwrap_or(false), + } + } + "matrix.read_messages" => MatrixServiceCall::ReadMessages { + limit: args["limit"].as_u64().unwrap_or(10).clamp(1, 30) as u32, + }, + "matrix.room_members" => MatrixServiceCall::Members { + limit: args["limit"].as_u64().unwrap_or(50).clamp(1, 200) as u32, + }, + "matrix.pinned_events" => MatrixServiceCall::PinnedEvents, + "matrix.room_threads" => MatrixServiceCall::Threads { + limit: args["limit"].as_u64().unwrap_or(20).clamp(1, 50) as u32, + }, + "matrix.send_message" => MatrixServiceCall::SendMessage { body: text_body(service, args)? }, + + // --- room --- + "matrix.thread_replies" => { + let Some(event_id) = args["event_id"].as_str().map(str::trim).filter(|s| !s.is_empty()) else { + return Err("matrix.thread_replies needs {event_id}".into()); + }; + MatrixServiceCall::ThreadReplies { + event_id: event_id.to_string(), + limit: args["limit"].as_u64().unwrap_or(50).clamp(1, 100) as u32, + } + } + "matrix.older_messages" => MatrixServiceCall::OlderMessages { + before: args["before"].as_str().map(str::trim).filter(|s| !s.is_empty()).map(str::to_string), + limit: args["limit"].as_u64().unwrap_or(20).clamp(1, 50) as u32, + }, + "matrix.event" => { + let Some(event_id) = args["event_id"].as_str().map(str::trim).filter(|s| !s.is_empty()) else { + return Err("matrix.event needs {event_id}".into()); + }; + MatrixServiceCall::Event { event_id: event_id.to_string() } + } + "matrix.read_receipts" => MatrixServiceCall::ReadReceipts { + user_id: args["user_id"].as_str().map(str::trim).filter(|s| !s.is_empty()).map(str::to_string), + }, + "matrix.unread" => MatrixServiceCall::Unread, + "matrix.power_levels" => MatrixServiceCall::PowerLevels, + "matrix.permalink" => { + let use_matrix_scheme = match args["scheme"].as_str().unwrap_or("matrix.to") { + "matrix.to" => false, + "matrix" => true, + _ => return Err("scheme must be \"matrix.to\" or \"matrix\"".into()), + }; + MatrixServiceCall::Permalink { + event_id: args["event_id"].as_str().map(str::trim).filter(|s| !s.is_empty()).map(str::to_string), + use_matrix_scheme, + } + } + "matrix.successor" => MatrixServiceCall::Successor, + + // --- rooms --- + "matrix.rooms_search" => { + let query = args["query"].as_str().map(str::trim).unwrap_or_default(); + if query.is_empty() { + return Err("matrix.rooms_search needs {query}".into()); + } + MatrixServiceCall::RoomsSearch { + query: query.to_string(), + limit: args["limit"].as_u64().unwrap_or(20).clamp(1, 50) as u32, + } + } + "matrix.invites" => MatrixServiceCall::Invites, + "matrix.room_preview" => { + let room = args["room"].as_str().map(str::trim).unwrap_or_default(); + if !room.starts_with(['!', '#']) { + return Err("matrix.room_preview needs {room}, a room id or alias".into()); + } + let via = args["via"].as_array() + .map(|v| v.iter().filter_map(|s| s.as_str().map(str::to_string)).collect()) + .unwrap_or_default(); + MatrixServiceCall::RoomPreview { room: room.to_string(), via } + } + "matrix.rooms_info" => MatrixServiceCall::RoomsInfo { + room_id: id_arg(service, args, "room_id", '!')?, + }, + "matrix.rooms_messages" => MatrixServiceCall::RoomsMessages { + room_id: id_arg(service, args, "room_id", '!')?, + limit: args["limit"].as_u64().unwrap_or(10).clamp(1, 30) as u32, + }, + + // --- spaces --- + "matrix.spaces" => MatrixServiceCall::Spaces, + "matrix.space_info" => MatrixServiceCall::SpaceInfo { + space_id: id_arg(service, args, "space_id", '!')?, + }, + "matrix.space_rooms" => MatrixServiceCall::SpaceRooms { + space_id: id_arg(service, args, "space_id", '!')?, + }, + + // --- account --- + "matrix.user_profile" => MatrixServiceCall::UserProfile { + user_id: id_arg(service, args, "user_id", '@')?, + }, + "matrix.dm_find" => MatrixServiceCall::DmFind { + user_id: id_arg(service, args, "user_id", '@')?, + }, + "matrix.device" => MatrixServiceCall::Device, + "matrix.account_info" => MatrixServiceCall::AccountInfo, + "matrix.ignored_users" => MatrixServiceCall::IgnoredUsers, + + // --- send --- + "matrix.reply" | "matrix.thread_reply" => MatrixServiceCall::Reply { + event_id: required_str(service, args, "event_id")?, + body: text_body(service, args)?, + in_thread: service == "matrix.thread_reply", + }, + "matrix.react" => { + let key = required_str(service, args, "key")?; + if key.chars().count() > 32 { + return Err("reaction key is too long (32 characters max)".into()); + } + MatrixServiceCall::React { event_id: required_str(service, args, "event_id")?, key } + } + "matrix.typing" => MatrixServiceCall::Typing { typing: required_bool(service, args, "typing")? }, + "matrix.read_receipt" => MatrixServiceCall::ReadReceipt { + event_id: args["event_id"].as_str().map(str::trim) + .filter(|s| !s.is_empty()) + .map(str::to_string), + }, + "matrix.pin" => MatrixServiceCall::Pin { + event_id: required_str(service, args, "event_id")?, + pinned: required_bool(service, args, "pinned")?, + }, + "matrix.favorite" | "matrix.low_priority" | "matrix.mark_unread" => MatrixServiceCall::RoomFlag { + flag: match service { + "matrix.favorite" => RoomFlag::Favorite, + "matrix.low_priority" => RoomFlag::LowPriority, + _ => RoomFlag::Unread, + }, + on: required_bool(service, args, "on")?, + }, + "matrix.rooms_send" => MatrixServiceCall::RoomsSend { + room_id: required_str(service, args, "room_id")?, + body: text_body(service, args)?, + }, + + // --- membership --- + "matrix.invite" => MatrixServiceCall::Invite { user_id: required_str(service, args, "user_id")? }, + "matrix.join" => MatrixServiceCall::Join { + room: required_str(service, args, "room")?, + via: args["via"].as_array() + .map(|v| v.iter().filter_map(|s| s.as_str().map(str::to_string)).collect()) + .unwrap_or_default(), + }, + "matrix.invite_respond" => MatrixServiceCall::InviteRespond { + room_id: required_str(service, args, "room_id")?, + accept: required_bool(service, args, "accept")?, + }, + "matrix.dm_open" => MatrixServiceCall::DmOpen { user_id: required_str(service, args, "user_id")? }, + + _ => return Err(format!("unknown service '{service}'")), + }) +} + +/// Request-budget price of a matrix service, in the limiter's tokens. +pub fn cost(service: &str) -> f64 { + match service { + // ----- room: answered from state the host already holds ----- + "matrix.room_info" | "matrix.unread" | "matrix.power_levels" | "matrix.permalink" + | "matrix.successor" => 1.0, + // ----- room: a worker round-trip ----- + "matrix.read_messages" | "matrix.room_members" | "matrix.pinned_events" + | "matrix.room_threads" | "matrix.search_room" | "matrix.thread_replies" + | "matrix.older_messages" | "matrix.event" | "matrix.read_receipts" => 5.0, + // ----- rooms: fans out over every room and may hit the network ----- + "matrix.rooms_list" => 5.0, + "matrix.search_rooms" => 8.0, + "matrix.rooms_search" | "matrix.invites" => 5.0, + "matrix.room_preview" | "matrix.rooms_messages" => 8.0, + "matrix.rooms_info" => 1.0, + // ----- account ----- + "matrix.profile" => 1.0, + "matrix.device" | "matrix.account_info" | "matrix.ignored_users" | "matrix.dm_find" => 1.0, + "matrix.user_profile" => 5.0, + // ----- send: speaks as the user ----- + "matrix.send_message" => 5.0, + "matrix.typing" => 1.0, + "matrix.favorite" | "matrix.low_priority" | "matrix.mark_unread" => 5.0, + "matrix.reply" | "matrix.thread_reply" | "matrix.react" | "matrix.read_receipt" + | "matrix.pin" | "matrix.rooms_send" => 8.0, + + // --- spaces --- + "matrix.spaces" => 5.0, + "matrix.space_info" => 1.0, + "matrix.space_rooms" => 8.0, + + // --- membership --- + "matrix.invite" | "matrix.join" | "matrix.invite_respond" | "matrix.dm_open" => 8.0, + + _ => 8.0, + } +} + +#[cfg(test)] +mod tests { + use super::*; + + fn parse_attached(service: &str, args: serde_json::Value) -> Result { + parse(service, &args, true) + } + + #[test] + fn room_services_need_a_room() { + for service in [ + "matrix.thread_replies", "matrix.older_messages", "matrix.event", "matrix.read_receipts", + "matrix.unread", "matrix.power_levels", "matrix.permalink", "matrix.successor", + ] { + let err = parse(service, &serde_json::json!({}), false).err(); + assert_eq!(err.as_deref(), Some("this mini-app is not attached to a room"), "{service}"); + } + } + + #[test] + fn thread_replies_needs_an_event_id_and_clamps_limit() { + assert!(parse_attached("matrix.thread_replies", serde_json::json!({})).is_err()); + assert!(parse_attached("matrix.thread_replies", serde_json::json!({"event_id": " "})).is_err()); + let MatrixServiceCall::ThreadReplies { event_id, limit } = + parse_attached("matrix.thread_replies", serde_json::json!({"event_id": " $root ", "limit": 500})).unwrap() + else { panic!("expected ThreadReplies") }; + assert_eq!(event_id, "$root"); + assert_eq!(limit, 100); + let MatrixServiceCall::ThreadReplies { limit, .. } = + parse_attached("matrix.thread_replies", serde_json::json!({"event_id": "$root"})).unwrap() + else { panic!("expected ThreadReplies") }; + assert_eq!(limit, 50); + let MatrixServiceCall::ThreadReplies { limit, .. } = + parse_attached("matrix.thread_replies", serde_json::json!({"event_id": "$root", "limit": 0})).unwrap() + else { panic!("expected ThreadReplies") }; + assert_eq!(limit, 1); + } + + #[test] + fn older_messages_takes_an_optional_anchor_and_clamps_limit() { + let MatrixServiceCall::OlderMessages { before, limit } = + parse_attached("matrix.older_messages", serde_json::json!({})).unwrap() + else { panic!("expected OlderMessages") }; + assert!(before.is_none()); + assert_eq!(limit, 20); + let MatrixServiceCall::OlderMessages { before, limit } = + parse_attached("matrix.older_messages", serde_json::json!({"before": " $e ", "limit": 99})).unwrap() + else { panic!("expected OlderMessages") }; + assert_eq!(before.as_deref(), Some("$e")); + assert_eq!(limit, 50); + let MatrixServiceCall::OlderMessages { before, limit } = + parse_attached("matrix.older_messages", serde_json::json!({"before": "", "limit": 0})).unwrap() + else { panic!("expected OlderMessages") }; + assert!(before.is_none()); + assert_eq!(limit, 1); + } + + #[test] + fn event_needs_an_event_id() { + assert_eq!( + parse_attached("matrix.event", serde_json::json!({})).err().as_deref(), + Some("matrix.event needs {event_id}"), + ); + let MatrixServiceCall::Event { event_id } = + parse_attached("matrix.event", serde_json::json!({"event_id": "$e"})).unwrap() + else { panic!("expected Event") }; + assert_eq!(event_id, "$e"); + } + + #[test] + fn read_receipts_user_is_optional() { + let MatrixServiceCall::ReadReceipts { user_id } = + parse_attached("matrix.read_receipts", serde_json::json!({})).unwrap() + else { panic!("expected ReadReceipts") }; + assert!(user_id.is_none()); + let MatrixServiceCall::ReadReceipts { user_id } = + parse_attached("matrix.read_receipts", serde_json::json!({"user_id": "@a:b"})).unwrap() + else { panic!("expected ReadReceipts") }; + assert_eq!(user_id.as_deref(), Some("@a:b")); + } + + #[test] + fn permalink_scheme_defaults_to_matrix_to() { + let MatrixServiceCall::Permalink { event_id, use_matrix_scheme } = + parse_attached("matrix.permalink", serde_json::json!({})).unwrap() + else { panic!("expected Permalink") }; + assert!(event_id.is_none()); + assert!(!use_matrix_scheme); + let MatrixServiceCall::Permalink { event_id, use_matrix_scheme } = + parse_attached("matrix.permalink", serde_json::json!({"event_id": "$e", "scheme": "matrix"})).unwrap() + else { panic!("expected Permalink") }; + assert_eq!(event_id.as_deref(), Some("$e")); + assert!(use_matrix_scheme); + assert!(parse_attached("matrix.permalink", serde_json::json!({"scheme": "https"})).is_err()); + } + + #[test] + fn argument_free_room_services_parse() { + assert!(matches!(parse_attached("matrix.unread", serde_json::json!({})), Ok(MatrixServiceCall::Unread))); + assert!(matches!(parse_attached("matrix.power_levels", serde_json::json!({})), Ok(MatrixServiceCall::PowerLevels))); + assert!(matches!(parse_attached("matrix.successor", serde_json::json!({})), Ok(MatrixServiceCall::Successor))); + } +} + +#[cfg(test)] +mod rooms_and_account_tests { + use super::*; + use serde_json::json; + + #[test] + fn rooms_search_needs_a_query_and_clamps_limit() { + assert!(parse("matrix.rooms_search", &json!({}), false).is_err()); + assert!(parse("matrix.rooms_search", &json!({"query": " "}), false).is_err()); + let Ok(MatrixServiceCall::RoomsSearch { query, limit }) = + parse("matrix.rooms_search", &json!({"query": " rust ", "limit": 500}), false) else { panic!() }; + assert_eq!((query.as_str(), limit), ("rust", 50)); + let Ok(MatrixServiceCall::RoomsSearch { limit, .. }) = + parse("matrix.rooms_search", &json!({"query": "x", "limit": 0}), false) else { panic!() }; + assert_eq!(limit, 1); + let Ok(MatrixServiceCall::RoomsSearch { limit, .. }) = + parse("matrix.rooms_search", &json!({"query": "x"}), false) else { panic!() }; + assert_eq!(limit, 20); + } + + #[test] + fn invites_parses_without_a_room() { + assert!(matches!(parse("matrix.invites", &json!({}), false), Ok(MatrixServiceCall::Invites))); + } + + #[test] + fn room_preview_takes_an_id_or_alias_and_via() { + assert!(parse("matrix.room_preview", &json!({}), false).is_err()); + assert!(parse("matrix.room_preview", &json!({"room": "matrix.org"}), false).is_err()); + let Ok(MatrixServiceCall::RoomPreview { room, via }) = + parse("matrix.room_preview", &json!({"room": "#robrix:matrix.org", "via": ["matrix.org", 7]}), false) else { panic!() }; + assert_eq!(room, "#robrix:matrix.org"); + assert_eq!(via, vec!["matrix.org"]); + let Ok(MatrixServiceCall::RoomPreview { room, via }) = + parse("matrix.room_preview", &json!({"room": "!abc:x"}), false) else { panic!() }; + assert_eq!(room, "!abc:x"); + assert!(via.is_empty()); + } + + #[test] + fn rooms_info_needs_a_room_id() { + assert!(parse("matrix.rooms_info", &json!({}), false).is_err()); + assert!(parse("matrix.rooms_info", &json!({"room_id": "#alias:x"}), false).is_err()); + let Ok(MatrixServiceCall::RoomsInfo { room_id }) = + parse("matrix.rooms_info", &json!({"room_id": " !abc:x "}), false) else { panic!() }; + assert_eq!(room_id, "!abc:x"); + } + + #[test] + fn rooms_messages_needs_a_room_id_and_clamps_limit() { + assert!(parse("matrix.rooms_messages", &json!({"limit": 5}), false).is_err()); + let Ok(MatrixServiceCall::RoomsMessages { room_id, limit }) = + parse("matrix.rooms_messages", &json!({"room_id": "!abc:x", "limit": 999}), false) else { panic!() }; + assert_eq!((room_id.as_str(), limit), ("!abc:x", 30)); + let Ok(MatrixServiceCall::RoomsMessages { limit, .. }) = + parse("matrix.rooms_messages", &json!({"room_id": "!abc:x"}), false) else { panic!() }; + assert_eq!(limit, 10); + } + + #[test] + fn space_services_parse() { + assert!(matches!(parse("matrix.spaces", &json!({}), false), Ok(MatrixServiceCall::Spaces))); + assert!(parse("matrix.space_info", &json!({}), false).is_err()); + assert!(parse("matrix.space_rooms", &json!({"space_id": "bad"}), false).is_err()); + let Ok(MatrixServiceCall::SpaceInfo { space_id }) = + parse("matrix.space_info", &json!({"space_id": "!s:x"}), false) else { panic!() }; + assert_eq!(space_id, "!s:x"); + let Ok(MatrixServiceCall::SpaceRooms { space_id }) = + parse("matrix.space_rooms", &json!({"space_id": "!s:x"}), false) else { panic!() }; + assert_eq!(space_id, "!s:x"); + } + + #[test] + fn user_services_need_a_user_id() { + assert!(parse("matrix.user_profile", &json!({}), false).is_err()); + assert!(parse("matrix.dm_find", &json!({"user_id": "alice"}), false).is_err()); + let Ok(MatrixServiceCall::UserProfile { user_id }) = + parse("matrix.user_profile", &json!({"user_id": "@alice:x"}), false) else { panic!() }; + assert_eq!(user_id, "@alice:x"); + let Ok(MatrixServiceCall::DmFind { user_id }) = + parse("matrix.dm_find", &json!({"user_id": "@alice:x"}), false) else { panic!() }; + assert_eq!(user_id, "@alice:x"); + } + + #[test] + fn account_services_parse_without_a_room() { + assert!(matches!(parse("matrix.device", &json!({}), false), Ok(MatrixServiceCall::Device))); + assert!(matches!(parse("matrix.account_info", &json!({}), false), Ok(MatrixServiceCall::AccountInfo))); + assert!(matches!(parse("matrix.ignored_users", &json!({}), false), Ok(MatrixServiceCall::IgnoredUsers))); + } +} + +#[cfg(test)] +mod send_tests { + use super::*; + use serde_json::json; + + fn parse_ok(service: &str, args: serde_json::Value) -> MatrixServiceCall { + parse(service, &args, true).unwrap_or_else(|e| panic!("{service} should parse: {e}")) + } + + fn parse_err(service: &str, args: serde_json::Value) -> String { + match parse(service, &args, true) { + Ok(_) => panic!("{service} should be rejected"), + Err(e) => e, + } + } + + #[test] + fn reply_needs_an_event_and_a_body() { + let MatrixServiceCall::Reply { event_id, body, in_thread } = + parse_ok("matrix.reply", json!({"event_id": "$e", "body": " hi "})) else { panic!() }; + assert_eq!(event_id, "$e"); + assert_eq!(body, "hi", "the body is trimmed"); + assert!(!in_thread); + assert_eq!(parse_err("matrix.reply", json!({"body": "hi"})), "matrix.reply needs {event_id}"); + assert_eq!(parse_err("matrix.reply", json!({"event_id": "$e", "body": " "})), "matrix.reply needs {body}"); + assert!(parse_err("matrix.reply", json!({"event_id": "$e", "body": "x".repeat(4097)})).contains("too long")); + assert!(matches!( + parse_ok("matrix.reply", json!({"event_id": "$e", "body": "x".repeat(4096)})), + MatrixServiceCall::Reply { .. } + )); + } + + #[test] + fn thread_reply_is_a_threaded_reply() { + let MatrixServiceCall::Reply { in_thread, .. } = + parse_ok("matrix.thread_reply", json!({"event_id": "$root", "body": "hi"})) else { panic!() }; + assert!(in_thread); + assert_eq!(parse_err("matrix.thread_reply", json!({"event_id": "$root"})), "matrix.thread_reply needs {body}"); + } + + #[test] + fn react_bounds_the_key() { + let MatrixServiceCall::React { event_id, key } = + parse_ok("matrix.react", json!({"event_id": "$e", "key": "👍"})) else { panic!() }; + assert_eq!((event_id.as_str(), key.as_str()), ("$e", "👍")); + assert_eq!(parse_err("matrix.react", json!({"event_id": "$e", "key": ""})), "matrix.react needs {key}"); + assert_eq!(parse_err("matrix.react", json!({"key": "👍"})), "matrix.react needs {event_id}"); + // Counted in chars, not bytes, so a multi-byte key isn't short-changed. + assert!(matches!( + parse_ok("matrix.react", json!({"event_id": "$e", "key": "é".repeat(32)})), + MatrixServiceCall::React { .. } + )); + assert!(parse_err("matrix.react", json!({"event_id": "$e", "key": "é".repeat(33)})).contains("32 characters")); + } + + #[test] + fn typing_needs_a_real_bool() { + assert!(matches!(parse_ok("matrix.typing", json!({"typing": true})), MatrixServiceCall::Typing { typing: true })); + assert_eq!(parse_err("matrix.typing", json!({"typing": "yes"})), "matrix.typing needs {typing: bool}"); + assert_eq!(parse_err("matrix.typing", json!({})), "matrix.typing needs {typing: bool}"); + } + + #[test] + fn read_receipt_event_is_optional() { + assert!(matches!(parse_ok("matrix.read_receipt", json!({})), MatrixServiceCall::ReadReceipt { event_id: None })); + assert!(matches!(parse_ok("matrix.read_receipt", json!({"event_id": " "})), MatrixServiceCall::ReadReceipt { event_id: None })); + let MatrixServiceCall::ReadReceipt { event_id: Some(id) } = + parse_ok("matrix.read_receipt", json!({"event_id": "$e"})) else { panic!() }; + assert_eq!(id, "$e"); + } + + #[test] + fn pin_needs_an_event_and_a_direction() { + assert!(matches!( + parse_ok("matrix.pin", json!({"event_id": "$e", "pinned": false})), + MatrixServiceCall::Pin { pinned: false, .. } + )); + assert_eq!(parse_err("matrix.pin", json!({"event_id": "$e"})), "matrix.pin needs {pinned: bool}"); + assert_eq!(parse_err("matrix.pin", json!({"pinned": true})), "matrix.pin needs {event_id}"); + } + + #[test] + fn room_flags_share_one_shape() { + assert!(matches!( + parse_ok("matrix.favorite", json!({"on": true})), + MatrixServiceCall::RoomFlag { flag: RoomFlag::Favorite, on: true } + )); + assert!(matches!( + parse_ok("matrix.low_priority", json!({"on": false})), + MatrixServiceCall::RoomFlag { flag: RoomFlag::LowPriority, on: false } + )); + assert!(matches!( + parse_ok("matrix.mark_unread", json!({"on": true})), + MatrixServiceCall::RoomFlag { flag: RoomFlag::Unread, on: true } + )); + assert_eq!(parse_err("matrix.mark_unread", json!({"on": 1})), "matrix.mark_unread needs {on: bool}"); + assert_eq!( + parse("matrix.favorite", &json!({"on": true}), false).err().unwrap(), + "this mini-app is not attached to a room" + ); + } + + #[test] + fn rooms_send_works_without_a_room_but_needs_one_named() { + assert!(matches!( + parse("matrix.rooms_send", &json!({"room_id": "!r:s", "body": "hi"}), false), + Ok(MatrixServiceCall::RoomsSend { .. }) + )); + assert_eq!(parse_err("matrix.rooms_send", json!({"body": "hi"})), "matrix.rooms_send needs {room_id}"); + assert_eq!(parse_err("matrix.rooms_send", json!({"room_id": "!r:s"})), "matrix.rooms_send needs {body}"); + assert!(parse_err("matrix.rooms_send", json!({"room_id": "!r:s", "body": "x".repeat(4097)})).contains("too long")); + } + + #[test] + fn invite_is_room_scoped() { + assert!(matches!(parse_ok("matrix.invite", json!({"user_id": "@u:s"})), MatrixServiceCall::Invite { .. })); + assert_eq!(parse_err("matrix.invite", json!({})), "matrix.invite needs {user_id}"); + assert_eq!( + parse("matrix.invite", &json!({"user_id": "@u:s"}), false).err().unwrap(), + "this mini-app is not attached to a room" + ); + } + + #[test] + fn join_takes_an_optional_via_list() { + let MatrixServiceCall::Join { room, via } = + parse("matrix.join", &json!({"room": "#a:s", "via": ["s", 7, "t"]}), false).unwrap() else { panic!() }; + assert_eq!(room, "#a:s"); + assert_eq!(via, ["s", "t"], "non-string servers are dropped"); + let MatrixServiceCall::Join { via, .. } = + parse("matrix.join", &json!({"room": "!r:s"}), false).unwrap() else { panic!() }; + assert!(via.is_empty()); + assert_eq!(parse("matrix.join", &json!({}), false).err().unwrap(), "matrix.join needs {room}"); + } + + #[test] + fn invite_respond_needs_a_room_and_an_answer() { + assert!(matches!( + parse("matrix.invite_respond", &json!({"room_id": "!r:s", "accept": false}), false), + Ok(MatrixServiceCall::InviteRespond { accept: false, .. }) + )); + assert_eq!( + parse("matrix.invite_respond", &json!({"room_id": "!r:s"}), false).err().unwrap(), + "matrix.invite_respond needs {accept: bool}" + ); + assert_eq!( + parse("matrix.invite_respond", &json!({"accept": true}), false).err().unwrap(), + "matrix.invite_respond needs {room_id}" + ); + } + + #[test] + fn dm_open_needs_a_user() { + assert!(matches!( + parse("matrix.dm_open", &json!({"user_id": "@u:s"}), false), + Ok(MatrixServiceCall::DmOpen { .. }) + )); + assert_eq!(parse("matrix.dm_open", &json!({"user_id": ""}), false).err().unwrap(), "matrix.dm_open needs {user_id}"); + } +} diff --git a/docs/adr/0005-octoscript-miniapps-matrix-octos.md b/docs/adr/0005-octoscript-miniapps-matrix-octos.md new file mode 100644 index 00000000..aa212fc0 --- /dev/null +++ b/docs/adr/0005-octoscript-miniapps-matrix-octos.md @@ -0,0 +1,118 @@ +# ADR 0005: Octoscript mini apps with Matrix and Octos services + +- Date: 2026-09-26 +- Status: Accepted; implemented and natively verified, with live model generation blocked by provider authentication +- Supersedes the general-runtime deferral in ADR 0002. The article editor and its grants remain supported. + +## Outcome + +An OctoSense Octoscript mini-app package can open inside Rinx, retain its native UI and state, call the A2App `matrix.*` API contract against the recipient's Matrix account, and use Octos sessions and tools. The same Rinx implementation serves standalone desktop/mobile builds and Rinx embedded in OctoSense. + +## Decision + +Use the existing Octoscript checker, kit lowering and Makepad Splash renderer. Reuse A2App's Matrix wire contract and SDK implementations, with Rinx owning authorization and dispatch. A mini app is a distinct instance with its own account, optional room, generation, storage and grants; the outer native Rinx module is not the mini-app identity. + +Expose Matrix and Octos through a single host-service boundary. Preserve A2App service names, argument validation and response shapes. Declarative `bindings.json` actions and imperative `host.request` calls converge on this boundary. Existing arbitrary `source sys.*` adapters are not automatically mapped to Matrix or Octos services. Do not rewrite an Octoscript package as a special Rinx UI or infer executable source from a chat message. + +Octos is a provider supplied by the host. In OctoSense, reuse the running core connection; a Rinx module must not start another kernel implicitly. Standalone Rinx can explicitly configure the same protocol provider. Lack of a provider is a visible unavailable result, never a fabricated response. A provider handle is distinct from the mini app's session, which belongs to its instance. + +The host authenticates request identity. Matrix credentials remain in Rinx and model credentials remain in Octos. A call must satisfy the package declaration, the host's capability limits and the current user's grants. The Matrix API adapter preserves room restrictions, account-change revocation and checks after asynchronous completion. App-to-Octos transfer of room data requires both the relevant Matrix read grant and the Octos grant. Publication remains an explicit host-authorized action. + +A host drains only requests belonging to its mini-app instances. Nested Rinx and OctoSense card hosts must not steal each other's callbacks. Closing an instance revokes its leases, cancels pending work and drops late replies; returning from the app does not terminate Rinx or the OctoSense shell. + +## Ownership + +| Component | Owner | +| --- | --- | +| Octoscript grammar, state transitions and widget kits | Octoscript / Octoscript-Makepad | +| Splash execution, widget rendering and isolate identity | Makepad | +| Portable package, grants and service contracts | Reusable mini-app host library | +| Matrix SDK session and A2App-compatible Matrix implementation | Rinx | +| Octos connection and kernel lifetime | Hosting application / configured standalone provider | +| App presentation, room attachment, sharing and navigation | Rinx | + +AI generation is optional. Importing and running an existing app must not require an agent. This implementation imports local Octoscript folders with explicit review. Signed App Hub catalog installation, A2App `.splashapp` import, and A2App watch/share lifecycle compatibility remain separate work; adopting the Matrix contract does not imply those import or lifecycle features exist. + +## Verification + +1. Check the existing A2App Matrix parser contract, grant denial, cross-room denial, instance revocation and late-reply handling. +2. Run the same Octoscript package through the shared renderer and Rinx host; exercise a state-changing input and a host-service result. +3. Exercise real Matrix and Octos protocol adapters, keeping protocol fixtures distinct from live-service results. +4. Verify standalone and OctoSense-hosted builds and native runtime behavior on macOS and Android. Confirm Back, keyboard handling, close/reopen, and that hosted Rinx reuses the Octos provider. +5. Record unverified platform/service combinations explicitly. A parser test, mocked provider or static screenshot alone is not end-to-end completion. + +## Implementation + +- `crates/miniapp-core` owns the A2App Matrix request parser, response bounds, instance leases, room grants and account-generation revocation. Matrix SDK adapters live in `src/octoscript_apps/matrix`. +- The native **Mini apps** page imports a digest-verified, bounded snapshot of a local bundle, reviews its services and optional room, and creates one account-scoped Splash instance. Closing it revokes requests and discards late responses. +- Current `main.splash` bundles use App Hub's shared script entry and asset-origin resolver. They call the same host services directly and keep their own script state. +- Octoscript-Makepad prepares the same L0 source, kit and state used by OctoSense cards. Input events update state; declarative bindings populate data fields from host replies. Rinx does not translate the example into a custom native screen. +- AppCard publishes its active `octos-app-transport::shared::Connection`. Hosted Rinx borrows that connection and allocates a distinct Octos session and UUID turns. AppCard replacement/disconnection invalidates the captured handle. Standalone Rinx can explicitly configure a remote provider. +- Only the native host supplies account, room, profile, workspace, session and approval identity. For a local core, account/app storage is allocated beneath the core data root from its native launch configuration (`--data-dir`, `OCTOS_HOME`, or child `HOME/.octos`). Remote connections do not imply shared local storage. The core workspace and explicit read allowlist both name the mini app's canonical data directory; tool network access is disabled. An empty read allowlist would inherit the core profile's broader access and must not be used. Bundle `agent` profiles are rejected until their additional budgets and tool limits can be honored. The mini app cannot call raw kernel RPC or approve its own tools. Runtime core tool permissions still require native approval. +- Makepad provides scoped host-queue draining and source reconciliation into existing named widgets. Android Back is dispatched into native navigation rather than finishing the activity. + +## Coordinated source baselines + +These changes span cooperating repositories. Rinx pins published dependency commits; OctoSense shells use their standard prepared source layout and source locks. Keep one Makepad package identity and one AppCard transport registry across all modules. + +| Repository | Baseline revision | +| --- | --- | +| Rinx | `47f46296` | +| OctoSense desktop | `57f4665c3d025e10465a035fd5221fee2ad143f5` | +| OctoSense ROM Home | `53329db1410d5aea446e5727f575f86c43660c8e` | +| Makepad (OctoSense's locked revision) | `1d3d383e84a66dbb18a4a860f505430c9d5b20f4` | +| Octoscript | `68f6a9df55692b5d8ef8873a12721e279a3f40d6` | +| Octoscript-Makepad | `c4c9682219d5bb549856e35086adf1b354844dc3` | +| OctoSense-System-Apps (AppCard workspace) | `4d99cb589d00207a9a63e32d46de6685843929d1` | +| Octos core | `18fcd3f16e527d2b601d7ae244f056fb711bb6b8` (`2.0.3-rc.12`) | +| App Hub policy | `4605128d46fb982828d8198e0d71d62a39c7d6d6` | + +Apply the shells' locked `makepad-contained-apps.patch` (source commit `d7a834c74783e2032bc9e2cb9e693eaa2927b1d9`, SHA-256 `70419d98644af0820816f8bbc480365fa214c71f96eea0dba4b541c7ec9d59a2`) over the Makepad baseline, then the Rinx source-reconciliation and Android navigation changes. Scoped host dispatch now comes from that upstream runtime patch. + +The developer checkouts are `Rinx`, `OctoSense-rinx-latest`, `OctoSense-ROM-rinx-latest`, `makepad-rinx-latest`, `octoscript-rinx-latest`, `octoscript-makepad-rinx-latest`, `OctoSense-System-Apps-rinx-latest` and `OctoSense-App-Hub-rinx-latest` under a common parent. The `*-rinx-latest` suffix is a local worktree name; revisions above identify the source baseline, with the coordinated working changes applied. + +See [the bundle guide](../../examples/miniapps/README.md) for the app format, service binding contract and example. Desktop builds belong to the OctoSense workspace; Android builds belong to the ROM's `home` workspace. The phone validation package is `dev.makepad.octosense.rinx`, separate from the installed launcher. Installing that APK updates Home application code for this test, not the device's underlying ROM image. + +## Validation record (2026-09-26) + +Remote `main` was checked again at 10:37 UTC: desktop `57f4665c` and ROM Home `53329db1`. Cargo metadata confirms both validation workspaces resolve the working `Rinx` checkout rather than the shell's released Rinx git pin. Runtime checks use native Metal on the MacBook and GLES on the OnePlus 6, with only the owned app's capture/input endpoints. + +| Check | Result | +| --- | --- | +| Portable request parsing, grants, account/room isolation and revocation | 30 tests pass | +| Rinx bundle admission, state updates, stream isolation and turn IDs | 7 tests pass | +| Shared transport, correlated replies and local storage configuration | 33 tests pass | +| AppCard store/render and remaining workspace tests | 45 tests pass; one transport doc test ignored | +| AppCard main library suite | 191 pass, 7 fail, 3 ignored; identical failures reproduced from clean `4d99cb5` app sources against the locked framework sources | +| AppCard workspace check and clippy (`--all-targets --no-deps -- -D warnings`) | Pass | +| Desktop native mini apps | Both bundle formats render; live Matrix profile and Octos session open/history work; continuous Chinese/emoji input, close/reopen, and one shared core process verified | +| Android native mini apps | Both bundle formats render; live Matrix profile, Octos session open/history, continuous input, keyboard dismissal and close/reopen work. A Back key and an actual system edge swipe each return to Rinx Discover without exiting Rinx; one shared core process verified | +| Live model generation | Not passed: the configured DeepSeek provider returns HTTP 401. No generated answer or tool-approval success is claimed | + +The seven baseline AppCard failures concern L0 exemplar/capability/theme drift: `every_call_the_lowering_emits_has_a_helper`, `the_nav_exemplar_is_the_card_the_profile_tests_check`, `l0_theme_axes_are_all_answered`, `a_live_source_without_its_capability_is_visibly_wrong`, `a_watch_row_reveals_its_own_remove`, `nav_is_generated_from_an_l0_spec`, and `the_language_reference_lists_every_admitted_theme`. They are not suppressed or weakened by this change. + +Native verification caught and fixed lost generated-label updates, missing font fallback in L0 inputs, the core profile's rejection of a workspace outside its read allowlist, and two Android Back deliveries from one key press. Parallel import tests caught a timestamp collision: admitted snapshots now use UUID names, and failed directory creation cannot acquire cleanup ownership over an existing snapshot. + +The phone's installed base image is `octosense-202609240442`, matching the latest local OTA in `rom-builds/20260924-display` (Android 15 / SDK 35). This work installs current ROM Home application code as `dev.makepad.octosense.rinx`; it does not flash a new system image or replace the normal `dev.makepad.octosense` launcher. Standalone Rinx is build-checked; its remote-provider UI has not been exercised against a separate live server. Write-side Matrix calls and native tool approvals were not exercised against live services. + +### Final validation artifacts + +Both release builds passed and were exercised natively. Paths below are relative to the common developer checkout parent; hashes identify the tested artifacts, including the coordinated working changes. + +| Artifact | Path | SHA-256 | +| --- | --- | --- | +| macOS executable | `OctoSense/target/release/octosense` | `d3321ce95393c5b606d67b56af932f15aa63e444cef5bdcaee399d7fa77440d5` | +| Android test APK | `OctoSense-ROM-rinx-latest/home/target/android/makepad-android-apk/octosense/apk/octo_senserinx.apk` | `9ebd5487876252695d2a365b70d7c02207617d2cc64979cd8b34386cd19585a8` | + +The owned desktop and phone test instances were closed after validation. The Android test APK remains installed for manual testing. The coordinated commits and PRs below publish the tested implementation. Dependency source identities and lockfiles were normalized after native validation; the recorded binary hashes identify the preceding native test builds. + +### Published dependency commits + +| Component | Commit | Pull request | +| --- | --- | --- | +| Makepad | `3fda5b6f9b48f390bd5396938a95d30ad035cd6d` | [PR](https://github.com/OctoSense-org/makepad/pull/32) | +| Octoscript-Makepad | `b9034566b0607c5bb8c04134d17139f99989e1d0` | [PR](https://github.com/OctoSense-org/OctoScript-Makepad/pull/40) | +| System Apps / AppCard | `1576bec6a585758e48c3252030cad2a9bf9c80db` | [PR](https://github.com/OctoSense-org/OctoSense-System-Apps/pull/4) | +| App Hub | `b0591e2caa0dc5c62927f7b85dbf826a50618a03` | [PR](https://github.com/OctoSense-org/OctoSense-App-Hub/pull/8) | + +The selected Makepad commit includes the containment patch already merged in Makepad #30. Consumers therefore clear the old overlay lock instead of applying that patch twice. Rinx Cargo metadata resolves one Makepad runtime, one Octoscript runtime, one AppCard transport, and one Octos core, with no task-specific local paths. diff --git a/examples/miniapps/README.md b/examples/miniapps/README.md new file mode 100644 index 00000000..f29136b2 --- /dev/null +++ b/examples/miniapps/README.md @@ -0,0 +1,40 @@ +# Octoscript mini apps in Rinx + +The `matrix-octos-script` example uses the current OctoSense `main.splash` bundle format and calls `host.request` directly. It reads a Matrix profile, opens and hydrates its own session on the shared core, and sends a model turn. + +The `matrix-octos` example is an ordinary L0 bundle: `page.card`, `page.data.json`, a kit, the OctoSense `manifest.json`, and declarative `bindings.json`. Rinx uses the shared Octoscript checker/lowerer for L0 and the shared App Hub entry resolver for `main.splash`, with native Makepad Splash widgets for both. Service results are live; the example does not substitute fixtures for Matrix or Octos. + +## Try it + +1. Log in to Matrix in Rinx. On desktop, choose **Mini apps** in the sidebar. On mobile, choose **Discover → Mini apps**. +2. In OctoSense, open AppCard once to connect its Octos core. Rinx captures that same connection when a mini app starts. Standalone Rinx offers an explicit Octos URL/profile/token form. +3. Enter the full path of the `matrix-octos-script` or `matrix-octos` folder, choose **Review bundle**, and review its declared services. Leave the room empty for this example. +4. Choose **Run**, then **Read my Matrix profile**. Edit the prompt and choose **Ask Octos**. Back revokes the app session and interrupts its active turn. + +For `main.splash`, service callbacks receive `{is_ok, data, error}`. The source and its `{{assets}}` URLs follow the same entry contract as App Hub. Script apps own their state and callbacks; `bindings.json` is only for L0. + +The importer currently accepts local unsigned bundles after explicit review. It does not install signed App Hub catalog packages or A2App `.splashapp` files. Room grants apply only to the room entered during review. Missing providers and failed calls are shown as errors. OS-specific services such as Mail account management are not exposed by this Rinx adapter. Bundle `agent` profiles are also rejected until all of their tool, budget and permission limits can be enforced. Octos service sessions explicitly narrow filesystem access to this app's data directory and disable tool network access. A remote standalone provider must be able to resolve that directory on its host; otherwise the core refuses the session. Bundled `os.*` system apps with an empty digest do not gain implicit trust when imported; a locally reviewed copy needs its digest generated. + +## Bind an event to a service + +```json +{ + "events": { + "refresh": {"service": "matrix.profile", "args": {}, "target": "profile"}, + "ask": {"service": "octos.turn.start", "args": {"text": {"$state": "prompt"}}, "target": "answer"} + } +} +``` + +Declare each service in `manifest.json` capabilities. Responses appear in the corresponding data field as `{"is_ok":true,"data":...}` or `{"is_ok":false,"error":...}`. Arguments can reference `{"$state":"field"}`, `{"$data":"/json/pointer"}` or `{"$value":true}`. A binding cannot provide account credentials, a core session ID, or an approval decision. Octos tool approvals use native host controls. + +After editing bundle bytes, regenerate the digest: + +```sh +cargo build --offline --manifest-path tools/miniapp-package/Cargo.toml +tools/miniapp-package/target/debug/rinx-miniapp-package examples/miniapps/matrix-octos +``` + +Each admitted instance runs from a verified snapshot. Editing the original package requires reviewing it again. Storage is confined to the current Matrix account and app ID. With a local shared core it lives beneath that core's configured data root, so session access can narrow the profile allowlist without widening it. Matrix-only / remote configurations use Rinx's data root. A custom core profile can still refuse the directory; Rinx does not relax that profile. + +The kit files are from Octoscript revision `68f6a9df55692b5d8ef8873a12721e279a3f40d6`; their MIT license is included in `kit/LICENSE`. The Matrix contract and adapters derive from A2App revision `d4d39612fdee574a0f6a33480a19868f1ec85644`, under the license retained in `crates/miniapp-core/LICENSE-MIT`. diff --git a/examples/miniapps/matrix-octos-script/main.splash b/examples/miniapps/matrix-octos-script/main.splash new file mode 100644 index 00000000..76093b44 --- /dev/null +++ b/examples/miniapps/matrix-octos-script/main.splash @@ -0,0 +1,35 @@ +fn read_profile(){ + ui.profile.set_text("Loading Matrix profile…") + host.request("matrix.profile", {}, fn(r){ + if r.is_ok { + ui.profile.set_text(r.data.display_name + " · " + r.data.user_id) + } else { ui.profile.set_text(r.error) } + }) +} +fn read_session(){ + ui.session.set_text("Opening Octos session…") + host.request("octos.session.open", {}, fn(r){ + if r.is_ok { + host.request("octos.session.history", {}, fn(h){ + if h.is_ok { ui.session.set_text(h.data.session_id) } + else { ui.session.set_text(h.error) } + }) + } else { ui.session.set_text(r.error) } + }) +} +fn ask(){ + ui.answer.set_text("Waiting for Octos…") + host.request("octos.turn.start", {text: ui.prompt.text()}, fn(r){ + if r.is_ok { ui.answer.set_text(r.data.text) } + else { ui.answer.set_text(r.error) } + }) +} +width: Fill height: Fill flow: Down padding: 16 spacing: 12 +Label {text: "Matrix + Octos" draw_text.text_style.font_size: 24} +profile := Label {width: Fill text: "Read your Matrix profile"} +Button {text: "Read Matrix profile" on_click: || read_profile()} +session := Label {width: Fill text: "Connect to the shared Octos core"} +Button {text: "Read Octos session" on_click: || read_session()} +prompt := TextInput {width: Fill text: "Say hello in one short sentence."} +Button {text: "Ask Octos" on_click: || ask()} +answer := Label {width: Fill text: ""} diff --git a/examples/miniapps/matrix-octos-script/manifest.json b/examples/miniapps/matrix-octos-script/manifest.json new file mode 100644 index 00000000..8653f114 --- /dev/null +++ b/examples/miniapps/matrix-octos-script/manifest.json @@ -0,0 +1,20 @@ +{ + "capabilities": [ + "matrix.profile", + "octos.session.open", + "octos.session.history", + "octos.turn.start", + "octos.turn.interrupt" + ], + "compute": { + "instruction_budget": 4000000, + "memory_bytes": 33554432 + }, + "id": "matrix-octos-script", + "integrity": { + "bundle_blake3": "78577bc28c749948c019b24514c7e6965ea8e57684620b32ed90850ccd3f65ce" + }, + "name": "Matrix + Octos script", + "schema": 1, + "version": "1.0.0" +} diff --git a/examples/miniapps/matrix-octos/bindings.json b/examples/miniapps/matrix-octos/bindings.json new file mode 100644 index 00000000..04665ca8 --- /dev/null +++ b/examples/miniapps/matrix-octos/bindings.json @@ -0,0 +1,6 @@ +{ + "events": { + "refresh": {"service":"matrix.profile","args":{},"target":"profile"}, + "ask": {"service":"octos.turn.start","args":{"text":{"$state":"prompt"}},"target":"answer"} + } +} diff --git a/examples/miniapps/matrix-octos/kit/LICENSE b/examples/miniapps/matrix-octos/kit/LICENSE new file mode 100644 index 00000000..dd6ae93f --- /dev/null +++ b/examples/miniapps/matrix-octos/kit/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Makepad B.V. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/examples/miniapps/matrix-octos/kit/_derive.octoscript b/examples/miniapps/matrix-octos/kit/_derive.octoscript new file mode 100644 index 00000000..4415d401 --- /dev/null +++ b/examples/miniapps/matrix-octos/kit/_derive.octoscript @@ -0,0 +1,47 @@ +// _derive.octoscript — every SIZE, computed from the knobs. +// +// Concatenated AFTER the mood's delta and before the kit, so a mood that moves +// `space_factor` or `radius_factor` moves everything that follows from it. Put +// these in the base instead and a delta could not reach them: `let` evaluates at +// its own line, so the derived value would already be fixed. +// +// The multipliers are the numbers the kit used to hardcode, so with the knobs at +// 1/10/2 the output is byte-identical to the shipped look. Four device goldens +// assert those numbers; the layer moves here, the look does not. + +// ---- spacing ------------------------------------------------------ +let pad_page_x = 20 * space_factor +// Clears the status bar AND leaves breathing room — but measured on device the +// system already insets the app below the bar: the page's own fill starts at +// y=102, under a black status area, so all 54 of these sat inside already-safe +// space and read as the screen's single largest void (173px, 7.4%). +// +// 36 rather than 0: a 24dp status bar still clears with margin if some window +// configuration ever stops insetting, and the point is to reclaim dead space, +// not to crowd the top edge. +let pad_page_top = 36 * space_factor +let pad_page_bot = 24 * space_factor // clears the gesture bar +let pad_panel_x = 14 * space_factor +let pad_panel_y = 12 * space_factor * media_stretch +let pad_tile_x = 12 * space_factor +let pad_tile_y = 10 * space_factor * media_stretch +let pad_chip_x = 10 * space_factor +let pad_chip_y = 5 * space_factor +let gap_panel_top = 16 * space_factor +let gap_row = 6 * space_factor +let gap_tile = 4 * space_factor + +// ---- radii -------------------------------------------------------- +let radius_panel = 14 * radius_factor +let radius_tile = 12 * radius_factor +let radius_chip = 12 * radius_factor + +// ---- the type scale ----------------------------------------------- +// One base and one step, as makepad's themes do it: `font_base` moves every size +// together (accessibility), `font_step` changes the CONTRAST between them. +let font_caption = font_base - font_step // 8 +let font_row = font_base // 10 +let font_body = font_base + font_step // 12 +let font_value = font_base + 2 * font_step // 14 +let font_title = font_base + 4 * font_step // 18 + diff --git a/examples/miniapps/matrix-octos/kit/_derive_color.octoscript b/examples/miniapps/matrix-octos/kit/_derive_color.octoscript new file mode 100644 index 00000000..cbcb280a --- /dev/null +++ b/examples/miniapps/matrix-octos/kit/_derive_color.octoscript @@ -0,0 +1,109 @@ +// _derive_color.octoscript — COLOUR derived from seeds, the way sizes always were. +// +// `_derive.splash` computes every size from four knobs; colours never got the +// same treatment, so each mood carried ~25 hand-written argb() literals and the +// accent axis needed 48 generated files — one per mood × hue, because a delta +// could not compute a tint against whatever ground the mood set. The missing +// piece was believed to be a rounding builtin; it existed all along, namespaced +// as `mod.math.round`, and the probe that "proved" its absence had called the +// bare name. +// +// Spliced AFTER the mood delta and the axis fragments, BEFORE `_derive.splash`. +// A fragment that wants a derived palette sets `seed_on = 1` and nine scalars; +// everything below then REBINDS the surface tokens from those seeds. With +// `seed_on = 0` (the base default) every rebind resolves to the token's prior +// value, so all six shipped moods render byte-identically — the goldens hold. +// +// The ink is a SEED, not a derivation: AA clamping is an iterative search that +// belongs in the generator that writes a ground fragment, not in a language +// with no loops. What derives here is the MECHANICAL system — the fills, +// hairlines and secondary inks that are relationships, not choices. + +fn dc_pick(c, a, b) { if c > 0 { return a } return b } +fn dc_mix(a, b, t) { return mod.math.round(a + (b - a) * t) } +// Perceived lightness, gamma-blind but monotonic — only ever used to pick a +// DIRECTION (toward white or toward black), never a ratio. +fn dc_lum(r, g, b) { return 0.2126 * r + 0.7152 * g + 0.0722 * b } + +// The far pole the panel lifts toward: away from wherever the ground sits. +let dc_dark = dc_lum(seed_ground_r, seed_ground_g, seed_ground_b) < 128 +fn dc_pole() { return dc_pick(dc_dark, 255, 0) } + +// DEFINED BELOW, after the accent solve rebinds the ink seeds. +// +// A function in this VM keeps the binding a name had when the function was +// DEFINED — asked on the device, the boot selftest logs the answer. Defined +// here, `dc_toward_ink` read the ORIGINAL `seed_ink_*` and never saw the +// accent-tinted values the solve below produces, so every ink it derives +// (l0_text, l0_soft, l0_dim) came out untinted and the whole accent-as-seed +// path was inert. A call may precede a definition, so moving the definitions +// past the rebinds is the entire fix. + +// ---- accent-as-seed: the ground x accent composition ---------------------- +// When BOTH a seeded ground and a seeded hue are present, the ink is pulled +// toward the hue as hard as this ground can carry: an UNROLLED five-step +// contrast solve (no loops in this language; five nested picks are the loop). +// The threshold is 4.9 against the ground — margin over AA's 4.5 to cover the +// panel lift, matching the offline auditor's math exactly. +fn dc_lin(c) { return mod.math.pow(c / 255, 2.2) } +fn dc_rlum(r, g, b) { + return 0.2126 * dc_lin(r) + 0.7152 * dc_lin(g) + 0.0722 * dc_lin(b) +} +fn dc_contrast(r1, g1, b1, r2, g2, b2) { + let a = dc_rlum(r1, g1, b1) + let b = dc_rlum(r2, g2, b2) + let hi = dc_pick(a > b, a, b) + let lo = dc_pick(a > b, b, a) + return (hi + 0.05) / (lo + 0.05) +} +fn dc_tint_ok(t) { + return dc_contrast( + dc_mix(seed_ink_r, seed_hue_r, t), dc_mix(seed_ink_g, seed_hue_g, t), + dc_mix(seed_ink_b, seed_hue_b, t), + seed_ground_r, seed_ground_g, seed_ground_b) >= 4.9 +} +let dc_t = dc_pick(dc_tint_ok(1.0), 1.0, + dc_pick(dc_tint_ok(0.85), 0.85, + dc_pick(dc_tint_ok(0.7), 0.7, + dc_pick(dc_tint_ok(0.55), 0.55, + dc_pick(dc_tint_ok(0.4), 0.4, 0.0))))) +let dc_both = seed_on * seed_hue_on +let seed_ink_r = dc_pick(dc_both, dc_mix(seed_ink_r, seed_hue_r, dc_t), seed_ink_r) +let seed_ink_g = dc_pick(dc_both, dc_mix(seed_ink_g, seed_hue_g, dc_t), seed_ink_g) +let seed_ink_b = dc_pick(dc_both, dc_mix(seed_ink_b, seed_hue_b, dc_t), seed_ink_b) +let seed_accent_r = dc_pick(dc_both, seed_hue_r, seed_accent_r) +let seed_accent_g = dc_pick(dc_both, seed_hue_g, seed_accent_g) +let seed_accent_b = dc_pick(dc_both, seed_hue_b, seed_accent_b) + +fn dc_toward_ink(t) { + return argb(255, dc_mix(seed_ground_r, seed_ink_r, t), + dc_mix(seed_ground_g, seed_ink_g, t), + dc_mix(seed_ground_b, seed_ink_b, t)) +} +fn dc_toward_pole(t) { + return argb(255, dc_mix(seed_ground_r, dc_pole(), t), + dc_mix(seed_ground_g, dc_pole(), t), + dc_mix(seed_ground_b, dc_pole(), t)) +} + +// The relationships, lifted verbatim from the E4 solver's shipped ratios. +let l0_base = dc_pick(seed_on, argb(255, seed_ground_r, seed_ground_g, seed_ground_b), l0_base) +let l0_base_2 = dc_pick(seed_on, dc_toward_pole(0.055), l0_base_2) +let l0_fill = dc_pick(seed_on, dc_toward_pole(0.07), l0_fill) +let l0_sheet = dc_pick(seed_on, dc_toward_pole(0.05), l0_sheet) +let l0_hairline = dc_pick(seed_on, dc_toward_ink(0.14), l0_hairline) +let l0_stroke = dc_pick(seed_on, dc_toward_ink(0.18), l0_stroke) +let l0_active = dc_pick(seed_on, dc_toward_ink(0.20), l0_active) +let l0_bar_rail = dc_pick(seed_on, dc_toward_ink(0.16), l0_bar_rail) +let l0_text = dc_pick(seed_on, dc_toward_ink(1.00), l0_text) +let l0_soft = dc_pick(seed_on, dc_toward_ink(0.90), l0_soft) +let l0_dim = dc_pick(seed_on, dc_toward_ink(0.66), l0_dim) +let l0_accent = dc_pick(seed_on, argb(255, seed_accent_r, seed_accent_g, seed_accent_b), l0_accent) +let l0_bar = dc_pick(seed_on, l0_accent, l0_bar) +let l0_go = dc_pick(seed_on, l0_accent, l0_go) +// A photo page never paints l0_base under its text; recolour the scrim the +// photo palette lays over the picture, keeping its alphas — the mechanism. +let l0_scrim_top = dc_pick(seed_on, + argb( 56, seed_ground_r, seed_ground_g, seed_ground_b), l0_scrim_top) +let l0_scrim = dc_pick(seed_on, + argb(242, seed_ground_r, seed_ground_g, seed_ground_b), l0_scrim) diff --git a/examples/miniapps/matrix-octos/kit/_kit.octoscript b/examples/miniapps/matrix-octos/kit/_kit.octoscript new file mode 100644 index 00000000..44848a1d --- /dev/null +++ b/examples/miniapps/matrix-octos/kit/_kit.octoscript @@ -0,0 +1,928 @@ +// _kit.octoscript — the L0 theme. +// +// `ui-profile-l0.md` §1.1: an L0 card names ROLES and never presentation. This +// file is a theme's answer to those roles — the layer the profile says must +// exist between a card and a backend: +// +// L0 card names roles TextHero, Panel, Chip, Tile +// ↓ +// THIS FILE role → presentation l0_hero, l0_panel, l0_chip, l0_tile +// ↓ +// octoscript-render DSL → UiNode renderer-free +// ↓ +// backend octoscript-makepad · Octoscript-OH · Octoscript-Android +// +// WHY IT DID NOT EXIST UNTIL NOW. The profile said "lowering targets the +// component kit" as though a kit answering L0's roles were sitting there. It was +// not: `components/flutter` and `components/material` are ports of Flutter +// samples, and against L0's 23 roles about four map loosely. What they DO +// provide is the primitive layer — `txt`, `gap`, `rule`, `spacer` — and that is +// what this is built from. +// +// THE PALETTE IS DELIBERATELY THE ONE ALREADY ON DEVICE. Every colour here is +// lifted from `octoscript-ui-l0`'s `makepad::lower`, which four goldens on a +// OnePlus 6T already assert. Changing the look and moving the layer at the same +// time would make a golden failure ambiguous between "the theme moved" and "the +// theme is wrong". Restyling comes after the move, against green goldens. +// +// EVERY ATTRIBUTE HERE IS ONE `octoscript-render` READS. Its `Attrs` is a fixed +// struct, not an open bag, so an attribute it does not name is not a default — +// it is silently discarded. A previous lowering attempt emitted roughly twenty +// such attributes and was reverted. + +// ---- palette --------------------------------------------------------------- +// NOT HERE. The palette is a separate file, concatenated BEFORE this one: +// `_palette_dark.splash` (the default), `_palette_light`, `_palette_glass`, +// `_palette_photo`. An L0 card declares `theme ` and the host picks the +// matching palette — that is §1.1's middle layer doing its job, and it is why a +// card can ask for dark without naming a colour. +// +// It has to come FIRST, not after: a function body resolves a name at its own +// declaration point, so a palette appended below would not reach the roles that +// read it. Rendering this file alone leaves every colour undefined — which +// coerces to 0, fully transparent — so every consumer concatenates a palette. + +// ---- primitives ------------------------------------------------------------ +// Self-contained rather than shared with the sample kits: those are ports of +// someone else's design system and will move for reasons that have nothing to +// do with L0. + +// `family` and `tracking` ride on EVERY text role, attached here rather than at +// each of the seven, because a card whose hero is serif and whose rows are sans +// is two designs. `l0_family` is "sans" in every base mood, so nothing moves +// until a card asks. +// +// `l0_display_family` is the DISPLAY face, used only where a role is a display +// role. A theme that pairs a serif headline with a sans body is the commonest +// pairing in the whole corpus, and one family token cannot express it. +fn l0_txt(s, size, weight, color) { + return {t: "text", text: s, size: size, weight: weight, color: color, fith: 1, + family: l0_family, tracking: l0_tracking, font_src: l0_font_src} +} + +// Text that may wrap. `fillw` is what lets it, and forcing it on a short hero +// wrapped "Top Movers" one character per line on device — so it is opt-in. +fn l0_para(s, size, weight, color) { + return {t: "text", text: s, size: size, weight: weight, color: color, + fillw: 1, fith: 1, family: l0_family, tracking: l0_tracking, font_src: l0_font_src} +} + +fn l0_gap(px) { return {t: "column", h: px} } +fn l0_spacer() { return {t: "column", fillw: 1, h: 1} } + +// ---- text roles ------------------------------------------------------------ +// A role says what a thing IS; the size ramp here is this theme's answer. + +// The ONE number a card exists to show. Sized by how long it is, because a hero +// is defined by dominating the card rather than by a point size: "18°" fits at +// 62 where "$184.20" clipped off the right edge. +// +// The CALLER measures and passes `pt`, and that is not an accident of interface +// design. Once a value lowers to a live backend call the drawn text is not in +// the DSL at all — `"$" + sys.stock("NVDA", "price")` renders as six characters +// and reads as thirty-three — so only the lowering knows what will be drawn. +// The display roles take `l0_display_family`, which is what makes a serif +// headline over sans body reachable. A theme setting only `l0_family` moves +// everything together; one setting only the display family moves the headline. +fn l0_display(node) { node.family = l0_display_family; return node } + +fn l0_hero(s, pt) { + // A hero over a full-bleed photograph does a different job than one in a + // list, and 43 was its ceiling (gap 2 of the mockup study). The factor + // scales only the TOP step — a short numeral — so a long text hero that + // already stepped down never doubles into a wall of 86pt wrap. + if pt >= 43 { return l0_display(l0_txt(s, pt * hero_factor, weight_hero, l0_text)) } + return l0_display(l0_txt(s, pt, weight_hero, l0_text)) +} + +// The type scale, TAKEN FROM THE WIDGETS THIS REPLACES rather than chosen. +// +// These are the sizes `octos-one`'s `TextTitle`, `TextBody`, `TextRow`, +// `TextCaption` and `TextValue` already carry, and four device goldens assert +// them. Moving the layer and restyling at once would make a golden failure +// ambiguous between "the theme moved" and "the theme is wrong" — so the theme +// does not move yet. Restyling comes after, against green goldens. +fn l0_title(s) { return l0_display(l0_txt(s, font_title, weight_bold, l0_text)) } +fn l0_body(s) { return l0_para(s, font_body, weight_normal, l0_text) } +fn l0_row_text(s) { + // `lines` is the theme's call, not the card's: a row that wraps to three + // lines breaks the list rhythm, and mid-word wrapping ("Thund erstorm") + // was visible in the round-2 corpus. + let node = l0_txt(s, font_row, weight_normal, l0_soft) + node.lines = row_lines + return node +} +fn l0_caption(s) { return l0_txt(s, font_caption, weight_normal, l0_dim) } +// The tracked-caps line above a hero. `variant` marks it for the backend, +// which spaces and uppercases a LITERAL — a live value stays as it arrives. +fn l0_eyebrow(s) { return {t: "text", text: s, size: font_caption, weight: weight_medium, + color: l0_soft, fith: 1, variant: "eyebrow"} } +fn l0_value(s) { return l0_txt(s, font_value, weight_semi, l0_text) } + +// A statistic, tinted by direction. `dir` is -1, 0 or 1 — the SIGN, decided by +// the card, not the colour: red-versus-green is presentation, but "this value +// fell" is meaning, and a lowering that dropped the attribute lost both. +fn l0_tint(dir) { + if dir > 0 { return l0_up } + if dir < 0 { return l0_down } + return l0_text +} +fn l0_stat(s, dir) { return l0_txt(s, font_row, weight_semi, l0_tint(dir)) } + +// Recolour any text by DIRECTION, composed around the role rather than folded +// into it. +// +// Every text role may carry a tint — the stock list tints a `TextValue`, the +// detail a `TextStat` — so the alternative was a direction parameter on all +// seven, six of which would pass 0 forever. `dir` of 0 leaves the role's own +// colour alone, which is what an untinted card gets. +fn l0_tinted(node, dir) { + if dir != 0 { node.color = l0_tint(dir) } + return node +} + +// Constrain a text role's WIDTH, composed around the role for the same reason +// `l0_tinted` is: any text role may carry `width`, and folding a parameter into +// all seven would have six passing a default forever. +// +// `fill` is what lets a long headline WRAP rather than run off the right edge. +// Every story title in the news list clipped until this existed — "A new +// approach to incremental c" — and a clipped title reads as a short one, so +// nothing on screen says the card is wrong. +fn l0_wide(node) { node.fillw = 1; return node } + +// The opposite, and it is NOT a no-op. `fit` is this backend's default for a +// text role, so `l0_wide`'s absence says it — but `l0_row` fills by default, +// because a list row must. A filling row inside a CENTRED column then ignores +// the centring: the weather card's `↑37° ↓28° ≈37°` sat hard left under a +// centred place name, icon and hero temperature, and no attribute the card could +// write changed it. `align` on a row means the CROSS axis, which is vertical. +fn l0_fit(node) { node.fillw = 0; node.fitw = 1; return node } + +// A fixed column, because these tokens name things that must LINE UP down a +// list: the rank numbers in a feed, the day names in a forecast. Fitting each +// to its own text ragged the column — "1" and "10" start at different x — so +// the card says WHICH column it is and the theme says how wide. +// +// The pixel counts live here and not in the lowering for the same reason the +// palette does: they are this theme's answer, and a different theme answers +// differently. +fn l0_colw(node, col) { + if col == "rank" { node.w = 28 } + if col == "day" { node.w = 44 } + if col == "temp" { node.w = 52 } + // A FORM LABEL: a fixed-width column that RIGHT-aligns what is in it, so the + // labels end where the fields begin instead of each one starting its field at + // its own x. "FROM" is wider than "TO", so fitting each to its text ragged the + // column exactly the way the rank numbers above ragged theirs. + // + // A WRAPPER, not `alignx` on the text. Alignment positions a widget inside its + // parent; it does not move the run inside the widget — the same thing the + // backend already learned about `TextInput`, where the container's `align` did + // nothing and `label_align` was the property that moved the text. Setting both a + // width and an alignment on the label itself left the run starting at the box's + // left edge and clipping off its right. + if col == "label" { + return {t: "column", w: 64, fith: 1, alignx: 1.0, c: [node]} + } + return node +} + +// Align a container's children on the CROSS axis — the axis the flow does not +// already decide. A column lays out downward, so aligning it is horizontal; a +// row lays out rightward, so aligning it is vertical. One token, one meaning, +// and the container knows which axis that is. +// +// The weather card centres its place name, its icon and its hero temperature, +// and that IS the screen's identity. Dropping the attribute left the whole +// header hard against the left margin — the card was right and looked wrong. +fn l0_aligned(node, how) { + if how == "center" { + // `Col(align: .center)` centres on ArkUI and does nothing on makepad, + // and giving the column `fillw` here does not close it: a makepad Label + // defaults to Fill width while an ArkUI text node hugs, so each child + // spans the centred column and still draws its glyphs at its own left + // edge. Measured — the hero stayed at x=166 of 750 with the column + // filling. Closing it means changing the text width default on one + // rail, across the whole corpus, which is its own pass. + if node.t == "row" { node.aligny = 0.5 } else { node.alignx = 0.5 } + } + if how == "end" { + if node.t == "row" { node.aligny = 1.0 } else { node.alignx = 1.0 } + } + return node +} + +// ---- containers ------------------------------------------------------------ + +// The page. Padding clears the status bar at the top and the gesture bar below. +// The page. `fith`, not `fillh`: a card is as tall as its content, and the host +// surface shows below it. Filling the height painted the whole screen in the +// card's base colour and covered the app's own background — 94% of the lower +// half differed, on a card whose content was correct. +// The page. Its fill is a two-stop VERTICAL gradient, not a flat colour. +// +// A judge scoring these renders called the flat moods "generic flat surfaces" +// with "no atmosphere", and scored the photo mood — the only one whose page is +// not a flat fill — on its atmosphere rather than against it. `bg2` is the same +// second stop the photo scrim already uses, so this is an existing, working +// capability applied where it was missing rather than anything new. +// +// A mood that wants a genuinely flat page sets `l0_base_2` equal to `l0_base`. +// `l0_texture` is the theme's surface grain, laid over the page by the backend. +// Empty in every base mood, so a card naming no texture emits the node it always +// did. The card never names the FILE — a texture is the theme's to choose for +// exactly the reason a colour is (profile §4), and the backend resolves the name. +fn l0_surface(kids) { + return {t: "column", fillw: 1, fillh: 1, bg: l0_base, bg2: l0_base_2, + gradient_across: l0_grad_across, + texture: l0_texture, texture_alpha: l0_texture_a, + texture_scale: l0_texture_s, + padx: pad_page_x, padtop: pad_page_top, padbottom: pad_page_bot, c: kids} +} + +// A page whose background is a photo, with a scrim so text stays legible over +// whatever the image turns out to be. +fn l0_surface_photo(src, kids) { + // A missing or pending photo must expose the kit's page, not the host black. + return {t: "stack", fillw: 1, fillh: 1, bg: l0_base, c: [ + {t: "image", src: src, fit: 2, fillw: 1, fillh: 1}, + // Two stops, not one wash: bright sky at the top, near-black under + // the content. The L1 immersive exemplar this mood was ported from had + // exactly this (GradientYView) and it was flattened on the way into + // L0 — the flat wash is why a forecast panel never read as floating + // out of the dark. `l0_scrim` stays the mood's strong BOTTOM stop; + // `l0_scrim_top` is the light one the photograph shows through. + {t: "column", fillw: 1, fillh: 1, bg: l0_scrim_top, bg2: l0_scrim}, + {t: "column", fillw: 1, fillh: 1, padx: pad_page_x, padtop: pad_page_top, padbottom: pad_page_bot, c: kids} + ]} +} + +// A page whose background is a MAP, with the card's own content floating over it +// as an opaque sheet. +// +// Every number here came off `a2app/apps/nav`, which has four maps and puts none +// of them in a column. A `MapView` is a fixed-pixel full-bleed surface that paints +// its route through the GPU nav projection rather than inside a laid-out rect, so +// stacked in a column beneath the card's content it draws straight over it — +// measured, the trip's FROM/TO fields, duration and Go button were invisible under +// the map, and in the driving view the route ribbon cut the turn banner in half. +// +// FIXED 812, not `fillh`: `Fill` inside a `Fit` parent resolves to 0 and a card is +// an item in a chat list, so filling rendered an entirely empty screen. +// +// The sheet is OPAQUE because the ordinary panel is 7% white, which over a map is +// a window — the map's own road labels read straight through the trip. And it sits +// at the BOTTOM because `update_plan_preview_camera` fits the route into the band +// ABOVE the summary sheet, so a sheet at the top lands exactly on the route it was +// making room for. 76 rather than the shipping card's 30 at the bottom: that card +// is full-screen, and an L0 card sits under the app's composer bar. +// Content a swipe reveals. Hidden until then; the renderer wires the toggle. +// +// NOT card state. A state change re-resolves the card, re-parses the document and +// rebuilds the `MapView` inside it — measured at up to 327 ms of frozen map. The +// shipping nav card toggles `ui.endrow.set_visible` directly for exactly this reason, +// and `action` is how the renderer is told which view to do that to. +fn l0_reveal(kids) { + return {t: "column", fillw: 1, action: "reveal", c: kids} +} + +// The top band, or nothing at all when nothing is docked there. `has` comes from +// the LOWERING because that is what knows whether the card docked anything; the kit +// has no way to ask a list its length. +fn l0_band(kids, has) { + if has == 0 { return {t: "column", fillw: 1, h: 0} } + return {t: "column", fillw: 1, fith: 1, bg: l0_sheet, radius: 18, + padx: 14, padtop: 10, padbottom: 10, c: kids} +} + +// The controls a map offers, top to bottom: the zoom pill, the current-location +// ring, then whatever the card docked to the side — which is where a view switch +// belongs, under the location button. +// +// Built HERE rather than inside `l0_map`: inside the map they sat at a fixed offset +// from its top and the instruction banner covered them, so the zoom pill's `+` was +// hidden behind it. In the surface's flow they come after the band and clear +// whatever it is tall, and there is ONE column instead of two clusters competing for +// the same corner. +fn l0_mapside(sidekids, hasside) { + if hasside == 0 { return {t: "column", h: 0} } + // No box of its own: each side control is a 38x38 circle (`l0_mapchip`), + // the same size as the recenter ring above it — the eye-test asked for the + // 2D/3D switch and the location button to match, and a text pill in a + // rounded panel could not. + return {t: "column", fitw: 1, fith: 1, alignx: 1.0, c: sidekids} +} + +// A side-docked map control: the card's own chip, drawn to the ring's spec. +// 38x38, the sheet's dark fill, the label centred — over pale tiles the +// generic sheet chip (`l0_fill` behind `l0_dim`) read as a grey smudge. +fn l0_mapchip(s) { + return {t: "column", w: 38, h: 38, radius: 19, bg: l0_sheet, + alignx: 0.5, aligny: 0.5, c: [l0_txt(s, 11, 600, l0_text)]} +} + +// Functions close over bindings that exist at declaration time. +fn l0_mapbtn(glyph, act) { + return {t: "column", w: 38, h: 38, alignx: 0.5, aligny: 0.5, action: act, + c: [l0_title(glyph)]} +} + +fn l0_rule() { return {t: "divider", fillw: 1, h: 1, bg: l0_hairline} } + +fn l0_mapcontrols(which, sidekids, hasside) { + let ring = {t: "column", fitw: 1, fith: 1, bg: l0_sheet, radius: 19, c: [ + {t: "column", w: 38, h: 38, alignx: 0.5, aligny: 0.5, action: "recenter", c: [ + // DRAWN, not typed: "◎" is U+25CE and the bundled Roboto has no glyph + // for it, so a typed one rendered as a tofu box. + {t: "column", w: 18, h: 18, radius: 9, bg: l0_text, + alignx: 0.5, aligny: 0.5, c: [ + {t: "column", w: 8, h: 8, radius: 4, bg: l0_sheet} + ]} + ]} + ]} + let pill = {t: "column", fitw: 1, fith: 1, bg: l0_sheet, radius: 14, c: [ + l0_mapbtn("+", "zoomin"), + l0_rule(), + l0_mapbtn("\u{2212}", "zoomout") + ]} + // NESTED, not concatenated. `[pill, gap] + sidekids` produced an empty column: + // the VM has no `+` for lists, so the whole expression evaluated to an error and + // every control vanished — the map kept its buttons only while they were built + // inside `l0_map` with literal lists. A column wrapping the card's own kids + // stacks them under the ring and needs no list arithmetic. + // + // The wrapper carries the pill's own dark backing, because whatever the card + // docked here is standing on MAP, not in a sheet. The nav card's 2D/3D switch is + // an ordinary `Chip`, and an ordinary chip is styled for a sheet: `l0_fill` + // behind `l0_dim`. Over pale tiles it read as a grey smudge — the label was + // there and could not be seen. `hasside` for the same reason `l0_band` takes + // `has`: the theme cannot ask a list its length, and an empty box drawn on every + // planning screen is the bug this kit already fixed once. + let docked = l0_mapside(sidekids, hasside) + if which == "none" { return [docked] } + if which == "zoom" { return [pill, l0_gap(10), docked] } + return [pill, l0_gap(10), ring, l0_gap(10), docked] +} + +fn l0_surface_map(map, topkids, sidekids, kids, hastop, controls, hasside) { + // TWO LAYERS, not four — the shape `a2app/apps/nav` uses for its driving screen. + // + // An earlier version stacked the map, a top-aligned layer and a bottom-aligned + // layer as three siblings, each `fillh` with its own alignment. It rendered, but + // it is not how the card being replaced does it, and every layer that fills the + // screen is another surface competing for the same hit tests. + // + // Theirs is one UI layer over the map, in a single `Down` flow: the top pane is + // simply the FIRST child, a `fillh` spacer eats the slack, and the sheet is LAST. + // No alignment tricks, one thing on top of the map, and the panes cannot overlap + // because a column cannot overlap itself. + // + // The paddings are theirs, except the bottom. 44 at the top clears the status + // bar and 10 at the sides are copied; 76 at the bottom replaces their 10, because + // their card is full-screen and an L0 card is an item in a chat list with the + // app's composer bar over it. Measured with 10: the sheet rendered below the + // visible area, cut off behind "Reconnecting…". Measured with 76: it cleared the + // bar by ~70 logical units and floated in the middle of the map. 52 still left + // 258px — 11% of the screen — of empty map between the sheet and the edge, which + // reads as the sheet hovering rather than resting. 14 put it UNDER the chrome — the copy/share row and the gesture bar overlay the + // bottom ~110px, and the sheet disappeared behind them. 40 rests it just clear: + // 52 left 258px of empty map below the sheet, 30 and 14 put it under the chrome. + return {t: "stack", fillw: 1, h: 812, bg: l0_base, c: [ + map, + // 56, raised from 40, and measured rather than tasted: with 40 the sheet's + // bottom sat within ~14dp of the clip line, and WHERE that line falls moves + // with the window's inset history — the same build rendered the bottom + // padding after a keyboard cycle and clipped it flat on a fresh boot, GO's + // rounding cut mid-pill. 56 keeps the sheet's padbottom and radius clear of + // the boundary wherever it lands. + {t: "column", fillw: 1, fillh: 1, padx: 10, padtop: 44, padbottom: 56, c: [ + // EMPTY MEANS ABSENT. A screen that docks nothing at the top still had + // the band drawn for it — a dark pill floating over the map saying + // nothing, on every planning screen. A container with no children is not + // a container. + l0_band(topkids, hastop), + {t: "column", fillw: 1, fith: 1, alignx: 1.0, padtop: 10, + c: l0_mapcontrols(controls, sidekids, hasside)}, + // The spacer. This is what puts the sheet at the bottom. + {t: "column", fillw: 1, fillh: 1}, + // CENTRED, like theirs: `remmin`/`remrest` are `align: Align{x: 0.5}` + // and the End bar spans the sheet. A driving summary is read at a + // glance, and a glance goes to the middle. + {t: "column", fillw: 1, fith: 1, bg: l0_sheet, radius: 22, + // Tight. The sheet sits over the map a driver is reading, so every + // unit of its height is map they cannot see: it covered 22% of the + // screen expanded. + // 4/8 was tuned for the DRIVE sheet, which is a handle over two lines + // of text. A planning sheet ends in a button, and 8 left it 7px off the + // sheet's own edge — reading as clipped whether or not it was. + padx: 14, padtop: 10, padbottom: 18, alignx: 0.5, + action: "sheet", c: kids} + ]} + ]} +} + +fn l0_col(kids) { return {t: "column", fillw: 1, c: kids} } +// A card writes its own `Col(gap: N)`, so this is the one place the KIT can +// still speak about that spacing — and §1.1 says spacing is the kit's to choose. +// +// A LARGE gap is "air", and what air reads as depends on the mood. The weather +// fixture's `gap: 36` is commented "the mockup's air — the half-screen of +// photograph": over a photo mood it frames the picture, over a flat fill it is +// simply a hole. Measured on device, the flat moods carried 540px of dead +// vertical space, 23% of the screen, and every mood's judge named that void as +// its biggest gap while the photo mood — same card — scored highest. +// +// So scale only the big gaps. Anything under 24 is deliberate fine spacing +// between related things and is left exactly alone. +fn l0_col_gap(g, kids) { + // Early return rather than reassigning a local inside the `if`: the first + // version did `let s = g` then `s = g * air_factor` in the branch, and the + // rendered dead space did not move a pixel (540 -> 543), so the mutation + // does not escape the block. `l0_colw` already branches by returning. + if g >= 24 { return {t: "column", fillw: 1, spacing: g * air_factor, c: kids} } + return {t: "column", fillw: 1, spacing: g, c: kids} +} +// A row centres its children vertically by default, because a row's whole job +// is to put unlike things side by side — a 44px icon beside 14pt text beside an +// 8px gradient bar — and top-aligning those reads as three separate things that +// happen to be adjacent. The reference rendering aligns every row this way. +fn l0_row(kids) { return {t: "row", fillw: 1, spacing: gap_row, aligny: 0.5, c: kids} } +fn l0_row_gap(g, kids) { return {t: "row", fillw: 1, spacing: g, aligny: 0.5, c: kids} } +// A grid of tiles. `w` is WIDTH IN PIXELS on the shared node model, and this +// said `w: 2` meaning "two columns" — so the stock card's six statistic tiles +// rendered in a box two pixels wide, which reads on screen as the card simply +// not having them. Neither backend implements a column count for a grid; both +// flow it downward like a column. Until one does, the honest thing is to fill +// the line and let the tiles stack. +fn l0_grid(kids) { return {t: "grid", fillw: 1, spacing: 10, c: kids} } +// The column that holds a grid's chunked rows. `l0_col` has no spacing, so +// grid rows fused vertically — a gallery of squares read as three solid +// columns. Rows breathe at the same gap the cells do. +fn l0_grid_rows(kids) { return {t: "column", fillw: 1, spacing: gap_row, c: kids} } + +// A raised surface holding related content. +fn l0_panel(kids) { + return {t: "card", fillw: 1, bg: l0_fill, radius: radius_panel, + padx: pad_panel_x, pady: pad_panel_y, margintop: gap_panel_top, + marginx: panel_inset, border: panel_border, bordercolor: l0_stroke, + elevation: panel_lift, + // The theme's shadow, when it has an opinion. Absent in every base + // mood, so a card that names no depth keeps the derived soft lift. + shadowcolor: l0_shadow_ink, shadowblur: l0_shadow_blur, + shadowdx: l0_shadow_dx, shadowdy: l0_shadow_dy, + c: kids} +} + +// A CONTENT card. Same box as a panel, but a pack may give it the design +// system's signature gradient: `l0_card_1 -> l0_card_2`, drawn by the view +// shader's own two-stop fill. Zero in every base mood, so nothing moves unless +// a pack asks — the Atro credit cards are the motivating screen. +// A card whose DESIGN colour differs from the pack gradient: the lower +// resolves the closed tint token to a pastel pair. +// +// A card also states the ink its own contents are read with. The card colour +// belongs to the PACK and does not flip when the pack's light variant flips +// the ink: CaMo light put near-black headlines on a pure black card and they +// simply were not there, on the desktop rail and the phone alike. `inkdark` +// used to mark that condition, and no renderer ever read the flag. `ink` +// carries the colour instead, and a renderer applies it to descending text +// that cannot be read against the card — text that already contrasts, an +// accent for instance, keeps its own colour. +fn l0_card_tinted(c1, c2, kids) { + let n = l0_panel(kids) + n.bg = c1 + n.bg2 = c2 + n.ink = l0_card_ink + return n +} + +// Chat bubbles: mine right and accent-filled, theirs left on the panel fill. +fn l0_bubble_me(s) { + return {t: "column", fillw: 1, alignx: 1, c: [ + {t: "card", fitw: 1, bg: l0_accent, radius: radius_panel, + padx: 12, pady: 7, c: [ l0_txt(s, font_body, weight_normal, l0_base) ]} ]} +} +fn l0_bubble_them(s) { + return {t: "column", fillw: 1, c: [ + {t: "card", fitw: 1, bg: l0_fill, radius: radius_panel, + padx: 12, pady: 7, c: [ l0_txt(s, font_body, weight_normal, l0_text) ]} ]} +} +// A LONG message wraps inside a capped-width bubble; single-line text would +// stretch the pill across the page (the lower picks by literal length). +fn l0_bubble_me_long(s) { + return {t: "column", fillw: 1, alignx: 1, c: [ + {t: "card", w: 252, bg: l0_accent, radius: radius_panel, + padx: 12, pady: 7, c: [ l0_para(s, font_body, weight_normal, l0_base) ]} ]} +} +fn l0_bubble_them_long(s) { + return {t: "column", fillw: 1, c: [ + {t: "card", w: 252, bg: l0_fill, radius: radius_panel, + padx: 12, pady: 7, c: [ l0_para(s, font_body, weight_normal, l0_text) ]} ]} +} + +// The floating round action button, and the overlay that pins it over a page. +// The bottom tab bar: a full-width row of icon+label tabs on the theme's bar +// rail, the active one lit in the accent. Nearly every app screen has one, and +// without it the model drew five "Item" captions in a flat strip. +fn l0_tab(glyph, label, active) { + let ink = l0_dim + if active > 0 { ink = l0_accent } + return {t: "column", fillw: 1, alignx: 0.5, gap: 3, c: [ + {t: "text", text: glyph, icon: 1, size: font_value, color: ink, fitw: 1, fith: 1}, + {t: "text", text: label, size: font_caption - 1, weight: weight_normal, color: ink} + ]} +} +fn l0_tabbar(kids) { + return {t: "row", fillw: 1, bg: l0_base_2, radius: radius_panel, + padx: 8, pady: 10, marginx: 0 - pad_page_x, c: kids} +} + +fn l0_fab(glyph) { + return {t: "card", w: 54, h: 54, radius: 27, bg: l0_go, elevation: 3, + alignx: 0.5, aligny: 0.5, + c: [ {t: "text", text: glyph, icon: 1, size: font_title, color: l0_base, + fitw: 1, fith: 1} ]} +} +// A page with a tab bar pinned to its floor: the page owns the top, the bar +// sits on the bottom, via the same aligned-layer trick as the pin surfaces. +fn l0_surface_tabbar(page, bar) { + return {t: "stack", fillw: 1, fillh: 1, c: [ + page, + {t: "column", fillw: 1, fillh: 1, aligny: 1, + padx: pad_page_x, padbottom: pad_page_bot, c: [bar]} + ]} +} + +fn l0_surface_fab(page, fab) { + return {t: "stack", fillw: 1, fillh: 1, c: [ page, + {t: "column", fillw: 1, fillh: 1, alignx: 1, aligny: 1, + padx: pad_page_x, padbottom: pad_page_bot, c: [ fab ]} ]} +} + +fn l0_card(kids) { + let n = l0_panel(kids) + if l0_card_2 > 0 { + n.bg = l0_card_1 + n.bg2 = l0_card_2 + n.ink = l0_card_ink + } + return n +} + +// A semantic icon: the glyph arrives already resolved (lower time), the size +// is a PLACE in the type scale, the ink is the theme's — so `icons: .mono` +// and an accent both reach it for free through l0_text. +fn l0_icon(glyph, size) { + if size == "hero" { return {t: "text", text: glyph, icon: 1, size: font_title * 1.6, color: l0_text, fitw: 1, fith: 1} } + if size == "tile" { return {t: "text", text: glyph, icon: 1, size: font_caption, color: l0_dim, fitw: 1, fith: 1} } + return {t: "text", text: glyph, icon: 1, size: font_value, color: l0_soft, fitw: 1, fith: 1} +} + +fn l0_avatar(s) { + // Initials in a tinted circle — the no-photo avatar every kit ships. + // A fixed 40px circle: radius half the box, accent fill, light ink. + return {t: "card", w: 40 * media_stretch, h: 40 * media_stretch, + radius: 20 * media_stretch, bg: l0_active, + padx: 10 * media_stretch, pady: 11 * media_stretch, fitw: 1, fith: 1, + c: [ l0_txt(s, font_caption, weight_semi, l0_ondark) ]} +} + + +// A labelled value — the unit a detail grid is made of. +// A calendar day: a fixed SQUARE cell — flat sheet, hairline border, the +// number centered, an optional event dot under it. A Panel here pills at the +// pack radius and grows with its dot; a day cell must not. +fn l0_tile_sq1(label) { + return {t: "card", w: 32, h: 32, radius: 4, bg: l0_sheet, + border: 1, bordercolor: l0_hairline, alignx: 0.5, aligny: 0.5, + c: [ l0_caption(label) ]} +} +// The dotted day flows from the top so the mark survives the fixed height: +// centering two stacked lines in 32pt clips the second one. +fn l0_tile_sq2(label, g) { + return {t: "card", w: 32, h: 32, radius: 4, bg: l0_sheet, + border: 1, bordercolor: l0_hairline, alignx: 0.5, + c: [ l0_caption(label), l0_caption(g) ]} +} +// A FULL-BLEED section band: escapes the page padding by its own margin and +// paints the theme's INVERSE — ink for ground, ground for ink — the way a +// month strip or a dark app-bar band sits edge-to-edge over a light page. +fn l0_band(txt) { + return {t: "card", fillw: 1, radius: 0, + marginx: 0 - pad_page_x, + bg: l0_soft, bg2: l0_dim, + padx: pad_page_x, pady: 9, + c: [ l0_txt(txt, font_title, weight_bold, l0_base) ]} +} + +// A row/column of day cells spreads at the CALENDAR's pitch, not the list +// gutter: fixed 32pt squares across a 341pt content width want ~16pt air. +fn l0_day_row(kids) { return {t: "row", fillw: 1, spacing: 16, aligny: 0.5, c: kids} } +fn l0_day_rows(kids) { return {t: "column", fillw: 1, spacing: 14, c: kids} } + +fn l0_tile(label, value) { + return {t: "card", fillw: 1, bg: l0_fill, radius: radius_tile, padx: pad_tile_x, pady: pad_tile_y, + c: [ l0_caption(label), l0_gap(gap_tile), l0_value(value) ]} +} + +// A selectable token. `on` is the card's own notion of selected — without it +// every chip in a range picker rendered identically and the card could not show +// which was chosen. +// A chip, selected or not. +// +// BRANCH AND RETURN rather than assign-then-patch. This was +// +// let fill = l0_panel +// if on == 1 { fill = l0_active } +// +// and the reassignment does not take in this VM: `fill` arrived at the node as 0, +// so every UNSELECTED chip was fully transparent. On a dark page that is a label +// with no button under it, which is what it looked like — the stock card's four +// unselected range chips, and a nav card's Go and End, all rendered as bare text. +// Nothing was missing and nothing was wrong except that none of them looked +// tappable. Found by live-testing on a phone, invisible to every unit test, +// because a colour of zero is a perfectly valid colour. +// +// A chip is INTRINSIC — as wide as its label plus its padding. Saying so matters +// because a tappable chip is wrapped in a fit-width hit target, and a fit wrapper +// around a child that never stated a width collapsed to nothing: all five range +// chips vanished from the stock detail, leaving a chart with no way to change its +// range and no sign that anything was gone. +// The action that ENDS something: full width, red, centred — the shipping nav card's +// `endrow`. A card says `tone: .danger`; which colour that is, and that it spans the +// sheet rather than hugging its label, is the theme's to decide. +fn l0_chip_danger(s) { + return {t: "chip", bg: l0_danger, radius: 12, padx: 10, pady: 12, + fillw: 1, alignx: 0.5, aligny: 0.5, + c: [ l0_txt(s, 11, 500, l0_danger_i) ]} +} + +// A destructive action scoped to ONE ROW — danger's colours in a chip's +// geometry. The full-width `l0_chip_danger` is a screen action (nav's Stop); +// this one sits beside the row it deletes, revealed by the card's own guard. +fn l0_chip_danger_row(s) { + return {t: "chip", bg: l0_danger, radius: 12, padx: 12, pady: 12, + aligny: 0.5, + c: [ l0_txt(s, 11, 500, l0_danger_i) ]} +} + +// The action a screen is FOR. `tone` says what an action means and the theme says +// how loud that is — a primary one is twice the type and a full round target, which +// is what an icon needs to be tappable at arm's length in a car. +fn l0_chip_primary(s) { + // GREEN, and the card does not say so. `tone: .primary` says "this is the action + // the screen is for"; that it reads as go — the same green iOS Maps uses, the + // same green this palette already spends on a rise — is the theme's answer. + // Sized like a button, not like a banner. At 20pt with 22/14 of padding this + // came out roughly 250x110 on a 1080-wide screen — a quarter of the sheet for one + // word. iOS Maps' GO is about 90x60 on a wider screen; 15pt with 24/9 lands in + // proportion and still gives a thumb somewhere generous to land. + return {t: "chip", bg: l0_go, radius: 14, padx: 24, pady: 9, selected: 0, + fitw: 1, fith: 1, c: [ l0_txt(s, 15, 700, l0_ondark) ]} +} + +fn l0_chip(s, on) { + if on == 1 { + return {t: "chip", bg: l0_active, radius: radius_chip, padx: pad_chip_x, pady: pad_chip_y, selected: 1, + fitw: 1, fith: 1, c: [ l0_txt(s, font_row, weight_medium, l0_text) ]} + } + return {t: "chip", bg: l0_fill, radius: radius_chip, padx: pad_chip_x, pady: pad_chip_y, selected: 0, + fitw: 1, fith: 1, c: [ l0_txt(s, font_row, weight_medium, l0_dim) ]} +} + +fn l0_photo(src) { return {t: "image", src: src, fit: 2, fillw: 1} } + +// A list row's image: fixed 16:9, so the text beside it keeps its baseline. +// A list-row 16:9 tile, a square mosaic cell, or a full-width hero media +// panel — the card names which (0/1/2), the kit owns the numbers. +fn l0_thumb(src, sq) { + if sq > 1 { return {t: "image", src: src, fit: 2, fillw: 1, h: 210 * media_stretch} } + if sq > 0 { return {t: "image", src: src, fit: 2, w: 102, h: 102} } + return {t: "image", src: src, fit: 2, w: 108, h: 61 * media_stretch} +} + +// A flexible blank: absorbs the leftover height of the column it sits in. +fn l0_space() { return {t: "column", fillh: 1} } + +// Aligned page layers. Deferred fills are greedy in the app's layout fork — +// anything walked after one never fits — so `Space()` splits the page into +// layers and ALIGNMENT does the pinning: `aligny: 1` sits a footer on the page +// floor, `0.5` centers a hero, with no fill arithmetic anywhere. +fn l0_surface_layer(kids, y) { + return {t: "column", fillw: 1, fillh: 1, aligny: y, + padx: pad_page_x, padtop: pad_page_top, padbottom: pad_page_bot, c: kids} +} +fn l0_surface_pin2(top, bottom) { + return {t: "stack", fillw: 1, fillh: 1, bg: l0_base, bg2: l0_base_2, + gradient_across: l0_grad_across, + texture: l0_texture, texture_alpha: l0_texture_a, + texture_scale: l0_texture_s, + c: [l0_surface_layer(top, 0), l0_surface_layer(bottom, 1)]} +} +fn l0_surface_pin3(top, mid, bottom) { + return {t: "stack", fillw: 1, fillh: 1, bg: l0_base, bg2: l0_base_2, + gradient_across: l0_grad_across, + texture: l0_texture, texture_alpha: l0_texture_a, + texture_scale: l0_texture_s, + c: [l0_surface_layer(top, 0), l0_surface_layer(mid, 0.5), + l0_surface_layer(bottom, 1)]} +} + +// ---- interaction ----------------------------------------------------------- +// A tap target, carried as `tapto` — an arbitrary string this renderer does not +// interpret. Its own `set:…` verbs are handled inside `octoscript-render`, and +// anything else falls through to the host, which is what lets an L0 event keep +// its instance key without any change to the VM. +// +// THE WRAPPER IS NOT DECORATION. A `card`, `chip` or `image` carrying `tapto` +// renders and does nothing: the attribute is accepted and then dropped, so the +// target string never reaches the UI at all. Only a container carries a tap. So +// a tappable role is wrapped in one, which is uniform and provable — deciding +// per role which kinds carry a tap natively is a second rule that rots the next +// time this renderer changes. +// +// Two variants because the wrapper must size like what it wraps. A chip is +// intrinsic and sits in a row of chips; wrapping it in a filling container makes +// the first chip eat the row. + +// The one role that receives something the user TYPED. +// +// `tapto` carries the commit target, exactly as it does for a tap — the backend +// turns it into whatever binds a return key, and the typed text becomes the +// payload. So text enters a card through the same declared, total path a tap +// does: `on_commit` names an event, the event writes declared state. +// Height is FIXED, not fitted. A text input is a control with a standing size +// rather than a box around its current contents, and every working input in +// this app states one — a fitted height also leaves the row's height dependent +// on text that has not been typed yet. +fn l0_field(text, placeholder, target, changing) { + // PADDED, not fixed-height. `h: 48` put the text at the top of a 48px box and + // every place name floated above the pill it was supposed to sit inside. Neither + // the container's `align` nor the input's `label_align` moved it — the run is laid + // out at the top of the turtle and the background is simply taller. + // + // Padding makes the pill grow around the text instead, so it is centred by + // construction: 14 above and below a 15pt run lands at the same 48 the fixed + // height was asking for, and it stays centred if the size ever changes. + return {t: "input", fillw: 1, text: text, placeholder: placeholder, + tapto: target, changeto: changing, bg: l0_fill, radius: 12, padx: 14, + padtop: 14, padbottom: 14, + // 15, not 17. A place name is the longest string a card puts in a + // fixed-width box, and at 17 "Saratoga High School" rendered as + // "Saratoga High Schoc" — clipped inside its own field, with no + // ellipsis to say so. The shipping nav card's search input is 15. + size: 11, color: l0_text} +} + +// A text node that carries its own LIVE CALL, so the renderer can refresh it in +// place instead of rebuilding the card around it. +// +// The kit evaluates a `sys.*` call to a string, and that string is all the renderer +// would otherwise see — so refreshing it meant re-resolving the ledger and re-parsing +// the whole document. On a driving screen that lands inside a frame: measured on a +// OnePlus 6, frame hitches and card re-resolves correlate 1:1, up to 327 ms of frozen +// map. The app this replaces never paid that: its card named its widgets and set +// their text from `fn tick()`. `action` carries the call so the renderer can emit +// the same thing. +fn l0_live(node, call) { + node.action = call + return node +} + +fn l0_tap(target, node) { + return {t: "column", fillw: 1, tapto: target, c: [node]} +} + +fn l0_tap_fit(target, node) { + // The wrapper hugs its content, so a Fill CHILD here resolves to a + // zero-width box (Fill inside Fit is 0 in makepad) — measured: a + // tap-wrapped live hero drew as an invisible column of one-glyph-wide + // wrapped lines, tiny at 17pt and a half-screen void at 43. A hug + // wrapper means hug content, so say it on the child as well. + node.fitw = 1 + return {t: "column", fitw: 1, fith: 1, tapto: target, c: [node]} +} + +// ---- data visualisations --------------------------------------------------- +// Six roles are small data visualisations rather than compositions of boxes and +// text: a gradient temperature bar is a fragment shader parameterised by data. +// +// `weathericon` is the one this renderer already has a kind for. The other five +// do NOT have one, and §1.1 records that as unsettled — `shader`/`sdf` with a +// variant is the mechanism this renderer documents, and adding five kinds +// obliges every backend at once. +// +// Until that is settled they render a VISIBLE marker. Returning nothing would +// let a card lose its temperature bars and still look complete, which is the +// failure mode §1.1 exists to prevent. + +// A trip, drawn. The card named two places and the ROUTE arrives already +// resolved — `poly` is an encoded polyline5, and `mode` is which member of the +// map family this is: a north-up preview of the whole route, a chase camera, or +// the same route drawn flat. +// +// How tall a map is, is the theme's answer, like every other role here — but the +// answer is CONSTRAINED, not free. The shipping nav card's mandatory rules say a +// `MapView` needs a fixed pixel height and that `Fill`/`Fit` "resolve to 0 and +// hide the map". 452 is that card's panel size, for a screen with content above +// the map; 812 is its full-bleed size. The first version here asked for 240 and +// drew a correct map in a letterbox. +// A map. `mode` is which member of the family; the centre and the route come +// resolved. +// +// A FOLLOW map's centre is not this one. `follow`/`follow3d` read the device's fix +// directly in the widget, every frame — a position that changes every second is not +// a property, and routing it through one froze the camera. The centre here is the +// trip's, which is what a preview needs and what a follow camera falls back to for +// the frame before the first fix lands. +// One control on a map: a fixed square that carries a glyph and an ACTION the +// backend turns into a call on the map. The card never names the call. +fn l0_map(mode, zoom, lat, lon, poly, pins, badge) { + // `pins` stands the trip's own endpoints on the route: green origin, blue + // stops, red destination. Derived from the SAME coordinates as `poly`, so a + // pin cannot mark a place the drawn line does not pass. + let m = {t: "navmap", fillw: 1, h: 812, + variant: mode, zoom: zoom, lat: lat, lon: lon, polyline: poly, + markers: pins, route_badge: badge} + return m +} + +// A condition, drawn. `cond` is a NUMBER — the WMO code the forecast returns — +// and `size` is which of the three places this icon sits in: the hero block, a +// forecast row, or a tile. The card says which; how big each is, is the theme's. +fn l0_icon_ink(node) { + // A mood that wants line-art restraint recolours the glyph to one ink + // (gap 8); 0 keeps the filled multi-colour icon. + if icon_mono != 0 { node.color = l0_text } + return node +} + +fn l0_weathericon(cond, size) { + if size == "hero" { return l0_icon_ink({t: "weathericon", variant: cond, w: 64, h: 64}) } + if size == "tile" { return l0_icon_ink({t: "weathericon", variant: cond, w: 28, h: 28}) } + return l0_icon_ink({t: "weathericon", variant: cond, w: 34, h: 34}) +} + +// The five that used to be markers. +// +// Each is a shader parameterised by data, so the kit chooses the SIZE — a +// theme's business — and the card supplies the numbers. Height matters here in a +// way it does not for text: a temperature bar is 8px of gradient and a contour +// field is a map, and neither has an intrinsic size to fit to. + +// A day's low and high against the week's range, as a gradient segment. +fn l0_tempbar(lo, hi, min, max) { + let node = {t: "tempbar", fillw: 1, h: 8, marginx: 10, + lo: lo, hi: hi, min: min, max: max} + // A mood that owns the bar palette says so (gap 7): rail + single hue + // instead of the nine-stop spectrum. `l0_bar` of 0 means legacy. + if l0_bar != 0 { node.bg = l0_bar_rail; node.bg2 = l0_bar } + return node +} + +// The sun's path, with now marked on it. Hours are fractional — 18.9 is 18:54. +fn l0_sunarc(rise, set, now) { + return {t: "sunarc", fillw: 1, h: 90, rise: rise, set: set, now: now} +} + +// 0..1 through the cycle, and percent illuminated. +fn l0_moonphase(phase, illum) { + return {t: "moonphase", w: 64, h: 64, phase: phase, illum: illum} +} + +// An air-quality field around a point. The widget fetches it: the card names +// WHERE, never the sixteen scalars a field would otherwise need. +// LIVE SATELLITE CLOUD IMAGERY (卫星云图) over a place. +// +// The one pane the shipping weather card has and L0 could not express: it names +// two coordinates and the helper answers a tile URL, so the card says WHERE and +// never what the sky looks like. Fetched here rather than passed in, for the same +// reason `l0_aqicontour` takes a location and not a grid — a card that carried +// the image would be carrying an observation. +fn l0_satellite(lat, lon) { + return {t: "image", src: sys.satellite(lat, lon), fit: 2, fillw: 1, h: 190} +} + +fn l0_aqicontour(lat, lon, span) { + return {t: "aqicontour", fillw: 1, h: 190, lat: lat, lon: lon, span: span} +} + +// A price series. Likewise: the card names WHICH series and over what window. +fn l0_stockplot(symbol, range) { + return {t: "stockplot", fillw: 1, h: 180, symbol: symbol, range: range, + color: l0_dim} +} + +// Several countries on one axis. The card names them and the indicator; the +// widget fetches, scales every series to one viewport, and draws its own +// legend — so the theme decides only the height it gets. +fn l0_indicatorplot(countries, indicator, years) { + return {t: "indicatorplot", fillw: 1, h: 210, + countries: countries, indicator: indicator, years: years} +} + +fn l0_unsupported(role) { + return {t: "card", fillw: 1, bg: l0_fill, radius: 8, padx: 10, pady: 8, + c: [ l0_caption("[" + role + " has no kind in this renderer]") ]} +} diff --git a/examples/miniapps/matrix-octos/kit/_palette_dark.octoscript b/examples/miniapps/matrix-octos/kit/_palette_dark.octoscript new file mode 100644 index 00000000..83b0cc64 --- /dev/null +++ b/examples/miniapps/matrix-octos/kit/_palette_dark.octoscript @@ -0,0 +1,215 @@ +// _palette_dark.octoscript — the BASE theme: every token, and the reference for the rest. +// +// A THEME IS A PALETTE PREFIX. The DSL has no `import`, so a card is rendered by +// concatenating + `_kit.splash` + the lowered card. The palette must +// come FIRST: a function body resolves a name at its declaration point, so a +// palette appended after the kit would not reach the roles that read it. +// +// ASSEMBLY IS `base + delta + _derive + kit`, in that order, and the order is +// load-bearing. This file holds the KNOBS and the COLOURS; a mood is a DELTA that +// restates only what differs; `_derive.splash` then computes every size FROM the +// knobs. Derivation has to come after the delta or a mood could not move a knob — +// `let` evaluates at its own line, so a delta setting `radius_factor` after +// `radius_panel` was already computed would change nothing. It works at all +// because a name resolves to its most recent binding and the kit's roles are +// declared last, after all three. +// +// A token this file omits is not a default: it coerces to 0, which is +// transparent for a colour and zero for a size, and the role that reads it draws +// nothing. `l0_palettes_agree` in `tests/l0_kit.rs` pins the set, and pins every +// delta to naming only tokens that exist here — a typo in a delta is otherwise +// silent. +// +// Hex from the shipped lowering, as ARGB. Note makepad writes #RRGGBBAA, so +// `#ffffff12` is white at alpha 0x12 — a barely-there panel over a dark page, +// not a near-white fill. + +fn argb(a, r, g, b) { return ((a * 256 + r) * 256 + g) * 256 + b } + +// ---- knobs ----------------------------------------------------------------- +// The whole point of Option A: a handful of dials, everything else derived from +// them, so a mood can be "dark but roomier" without restating a layout. Values +// are 1 / 10 / 2 because that reproduces the shipped numbers EXACTLY — the layer +// moves here, the look does not. Four device goldens assert those numbers. +// +// Integers on purpose. A fractional `space_factor` is legal and yields floats, +// which every size slot accepts; the TYPE scale is dialled with `font_base` and +// `font_step` instead, so a larger-text theme does not have to risk a fractional +// font size. +let space_factor = 1 +let radius_factor = 1 +let font_base = 10 +let font_step = 2 + +// ---- weights --------------------------------------------------------------- +// Not derived: a weight is a discrete choice from what a font actually ships. +let weight_normal = 400 +let weight_medium = 500 +let weight_semi = 600 +let weight_bold = 700 +// The one number a card exists to show gets its own axis: a hero over a +// list is bold; a hero over a photograph wants a hairline. Moods dial it. +let weight_hero = 700 +// The hero's top-step multiplier; only a surface whose hero dominates a +// photograph moves it (see l0_hero). +let hero_factor = 1 +// Data-vis restraint knobs: 0 = the widget's legacy look. +// A single hue on a faint rail, not the nine-stop spectrum. +// +// Same natural experiment that decided `icon_mono`: `photo` was the only mood +// carrying these and the only one a judge did NOT accuse of "spectral gradient +// bars that break the restrained palette". A rainbow ramp also encodes nothing +// — the bar's LENGTH already carries the range — so the spectrum is decoration +// competing with the type for attention. +let l0_bar = argb(255, 109, 121, 240) // #6d79f0 indigo + +// The base's own accent, under the name the derivation reads. +// +// Nothing bound `l0_accent` unless a card named an accent AXIS, and +// `_derive_color` reads its previous binding — so every base mood errored once +// and painted the accent fully transparent, silently, because 0 is a legal +// colour. The value is not invented here: `l0_bar` above IS this palette's +// accent, and an accent fragment says so explicitly (`l0_bar = l0_accent`). +// A fragment spliced later still overrides this. +let l0_accent = l0_bar +let l0_bar_rail = argb( 41, 255, 255, 255) // #ffffff29 faint rail on a dark page +// Single-ink glyphs, not the filled multi-colour ones. +// +// A natural experiment decided this. Scoring the four moods, `photo` was the +// only one carrying `icon_mono = 1` and the only one a judge did NOT accuse of +// "system emoji icons instead of custom iconography" — the other three, all at +// 0, were each flagged for it. A filled multi-colour cloud reads as a stock +// emoji dropped into the card; recoloured to the text ink it reads as the +// card's own iconography. +let icon_mono = 1 +let l0_font_src = "" +// A floating pane's side inset; 0 = the classic full-bleed panel. +let panel_inset = 0 +// One line per list row, with an ellipsis. 0 would mean unlimited. +let row_lines = 1 +// A surface outline. 0 = none; the mood supplies both width and ink. +let panel_border = 0 +// How high a panel floats. 0 = flat, which is this mood's answer; a mood that +// wants a raised card dials it up and `Attrs.elevation` casts the shadow. +let panel_lift = 0 +// How much of a card's own large `Col(gap:)` survives. 1 keeps every pixel of +// the card's air, which is right when a photograph fills it. A flat mood has +// nothing behind that air, so it reads as a hole and is tightened. +let air_factor = 0.62 + +// ---- colours --------------------------------------------------------------- +// The canonical page colour, and the TOP of the fall — deliberately NOT lifted. +// +// An earlier attempt made the gradient visible by raising this to #131a25. That +// worked (fall 5 -> 11) but paid for it where it hurts: the hero's contrast +// against the page fell from 11.0:1 to 8.0:1, and a judge immediately called +// the text contrast low. Deepening the BOTTOM instead buys a LARGER fall for +// free, because the top is where the type sits and the bottom is where the +// content has already ended. +let l0_base = argb(255, 10, 14, 20) // #0a0e14 page, top of the fall +// The page's second stop. A page that is one flat colour reads as a default +// rather than a decision; a few levels of vertical fall gives it a horizon. +// The BOTTOM stop, taken to near-black. Fall of 13 levels — more than lifting +// the top achieved — and the hero keeps its full 11:1. +let l0_base_2 = argb(255, 0, 1, 3) // #000103 +let l0_scrim = argb(102, 0, 0, 0) // #00000066 photo scrim, bottom stop +let l0_scrim_top = argb( 34, 0, 0, 0) // #00000022 photo scrim, top stop +// A sheet floating over a MAP, and the one fill in this palette that must be +// fully opaque. `l0_fill` is 7% white, which is a window rather than a surface: +// over a map the road labels read straight through whatever the card put there. +// The colour is the shipping nav card's own sheet. +let l0_sheet = argb(255, 15, 22, 32) // #0f1620 over a map +// The one action that ENDS something. Values from the shipping nav card's `endrow`. +let l0_danger = argb(255, 122, 31, 31) // #7a1f1f destructive fill +let l0_danger_i = argb(255, 255, 217, 217) // #ffd9d9 its ink +// NOT `l0_panel`, and the name is the whole point. +// +// `fn l0_panel(kids)` is a ROLE in the kit, so a palette entry of the same name +// is shadowed by it from the function's declaration onward — and a function +// coerced to a colour is 0. Every use after `fn l0_panel` silently became fully +// transparent: `l0_chip` and `l0_field` both asked for this fill and both got +// nothing. Uses INSIDE `l0_panel`'s own body still resolved to the colour, which +// is why panels looked right and chips did not, and why it read as a chip bug. +// +// Found by live-testing a nav card on a phone: Go and End rendered as bare text +// with no button under them. No unit test could see it — zero is a valid colour. +let l0_fill = argb( 18, 255, 255, 255) // #ffffff12 panel fill +let l0_active = argb( 56, 255, 255, 255) // #ffffff38 selected chip +let l0_hairline = argb( 26, 255, 255, 255) // #ffffff1a divider +// The surface outline's ink. Declared HERE, after `l0_hairline`, and not up with +// the other stroke knobs: `let` evaluates at its own line, so reading a colour +// declared 27 lines below yielded an unresolved name — which coerces to 0, a +// fully transparent stroke. That is why borders emitted at the right width and +// painted nothing. +let l0_stroke = l0_hairline +let l0_text = argb(255, 255, 255, 255) // #ffffff primary +let l0_soft = argb(230, 255, 255, 255) // #ffffffe6 secondary +let l0_dim = argb(153, 255, 255, 255) // #ffffff99 captions and labels +let l0_up = argb(255, 50, 215, 75) // #32d74b a rise +let l0_go = argb(255, 52, 199, 89) // #34c759 the action a screen is for +let l0_ondark = argb(255, 14, 22, 32) // #0e1620 text on a lit fill +let l0_down = argb(255, 255, 69, 58) // #ff453a a fall + +// The theme's surface grain. Empty here: the base moods are flat, and a +// texture arrives only when a card names one on its theme line. +let l0_texture = "" +let l0_texture_a = 0.06 +let l0_texture_s = 6 + +// The theme's shadow. Zero ink means "no opinion": the backend keeps the +// soft shadow it derives from `elevation`, which is what every mood shipped +// before a card could ask for anything else. +let l0_shadow_ink = argb(0, 0, 0, 0) +let l0_shadow_blur = 0 +let l0_shadow_dx = 0 +let l0_shadow_dy = 0 + +// Type. `sans` in every base mood, so a card naming no type axis renders the +// face it always did. The display family is separate so a serif headline over +// a sans body — the commonest pairing in the corpus — is one axis, not two. +let l0_family = "sans" +let l0_display_family = "sans" +let l0_tracking = 0 + +// Which way the page gradient runs. Down in every base mood, which is what +// the shader defaulted to anyway — now it is a choice rather than the only +// branch anything ever took. +let l0_grad_across = 0 + +// The colour-seed switch. Zero everywhere by default: `_derive_color` +// then leaves every token exactly as the mood wrote it, so the six +// shipped moods render byte-identically. A `ground:` fragment flips it +// and supplies the nine seeds. +let seed_on = 0 +let seed_ground_r = 0 +let seed_ground_g = 0 +let seed_ground_b = 0 +let seed_ink_r = 0 +let seed_ink_g = 0 +let seed_ink_b = 0 +let seed_accent_r = 0 +let seed_accent_g = 0 +let seed_accent_b = 0 + +// The content-card gradient. Zero = flat (every base mood); a pack sets +// both stops to give its cards the design system's signature fill. +let l0_card_1 = 0 +let l0_card_2 = 0 +// The ink that card reads with. A pack's card colour is part of its identity +// and stays put across the pack's light and dark variants, while `l0_text` +// flips — so a card states its own ink rather than borrowing the page's. +// Unused while the stops are zero, since then a card is just a panel. +let l0_card_ink = argb(255, 255, 255, 255) + +// The accent-as-seed switch: an accent fragment sets the hue; only when a +// seeded ground is ALSO present does the in-kit solve replace the mood- +// solved literals. +let seed_hue_on = 0 +let seed_hue_r = 0 +let seed_hue_g = 0 +let seed_hue_b = 0 + +// Frame-fill stretch: >1 grows media heights and card paddings so a +// sparse card fills its design frame. 1 everywhere but the fidelity +// harness, which measures dead space and re-renders with the ratio. +let media_stretch = 1 diff --git a/examples/miniapps/matrix-octos/kit/_palette_light.octoscript b/examples/miniapps/matrix-octos/kit/_palette_light.octoscript new file mode 100644 index 00000000..098d2a32 --- /dev/null +++ b/examples/miniapps/matrix-octos/kit/_palette_light.octoscript @@ -0,0 +1,71 @@ +// _palette_light.octoscript — the `light` mood, as a DELTA over `_palette_dark`. +// +// Assembled `base + this + kit`, so it restates only what differs. It may name +// any token the base defines and no others: a name the base does not have is a +// new binding the kit never reads, which is silent. `l0_palettes_agree` checks it. +// +// Values are the shipped light weather style's own (a2app/apps/weather/ +// exemplars/style-light.octoscript), so a card that used to ask for "minimal +// weather" and get a hand-authored DSL template lands on the same colours +// through the kit instead. + +let l0_base = argb(255, 242, 242, 247) // #f2f2f7 page +// OPAQUE, not a white-on-white alpha. On a dark page a 7% white fill reads as a +// panel; on a #f2f2f7 page the same alpha is invisible, so the light mood needs +// the style's actual card colour and its actual hairlines. +let l0_fill = argb(255, 255, 255, 255) // #ffffff panel fill +let l0_active = argb(255, 226, 226, 231) // #e2e2e7 selected chip +let l0_hairline = argb(255, 236, 236, 241) // #ececf1 divider +let l0_sheet = argb(255, 255, 255, 255) // #ffffff over a map — opaque +let l0_text = argb(255, 28, 28, 30) // #1c1c1e primary +let l0_soft = argb(255, 72, 72, 76) // #48484c secondary +// #6d6d6e captions and labels. Was #8e8e93, which is 2.92 against this +// mood's page — below AA and below even the large-text floor, so every caption +// in the light mood was under-contrast. Nothing measured it: the auditor +// checked the PRIMARY ink only, and captions do not use the primary ink. +// Darkened along its own faint blue cast until the page pair clears AA (4.63; +// 5.17 on the panel). The other moods were already fine: dark 7.28, camo light +// 6.17, atro light 6.47. +let l0_dim = argb(255, 109, 109, 110) +let l0_up = argb(255, 30, 160, 60) // #1ea03c darkened to read on white +let l0_down = argb(255, 215, 58, 73) // #d73a49 a fall +let l0_danger = argb(255, 215, 58, 73) // #d73a49 destructive fill +let l0_danger_i = argb(255, 255, 255, 255) // #ffffff its ink +let l0_ondark = argb(255, 255, 255, 255) // #ffffff text on a lit fill + +// NOT overridden, deliberately: +// l0_scrim — over a photo a light scrim washes the image out AND leaves dark +// ink unreadable. The scrim exists for legibility over an image, not to +// match the page, so the base's dark one is right here too. +// l0_go — #34c759 reads on both. +// every SIZE token — this mood is a repaint, not a relayout. + +// A hairline outline instead of relying on fill alone: on a light page a +// panel with no edge dissolves into the ground, which is what the material +// and pastel schools kept being marked down for. +let panel_border = 1 +// A light theme is where a raised surface reads: a card on near-white needs a +// shadow to separate from the page, where the dark mood separates by fill alone. +// Delivery-gated on device 2026-08-30: this darkens the page by 44 luminance +// levels just below the card edge. +let panel_lift = 6 +// A light theme is where a raised surface reads: a card on near-white needs a +// shadow to separate from the page, where the dark mood separates by fill alone. +let l0_stroke = argb( 38, 0, 0, 0) // #00000026 a quiet edge + +// The base's rail is white at 16%, which vanishes on a near-white page. +let l0_bar_rail = argb( 26, 0, 0, 0) // #0000001a a rail that reads on light + +// Light's page DEEPENS downward, away from the card, not toward it. +// +// The first version of this lifted the page to #ffffff — which is exactly +// `l0_fill`, the card's own colour — so the card dissolved into the page at the +// bottom of the screen. A judge scoring that build called it "near-white" with +// "flat low-contrast surfaces", which is precisely the merge described. +// A gradient behind a surface has to move AWAY from that surface's fill. +let l0_base_2 = argb(255, 232, 232, 240) // #e8e8f0 deeper than the page top + +// Same measurement on a white card: the base's indigo is 1.92:1 there, so the +// bar reads as a pale smudge. On white the separation has to come from going +// DEEPER. +let l0_bar = argb(255, 61, 72, 184) // #3d48b8 2.96:1 on the white card diff --git a/examples/miniapps/matrix-octos/manifest.json b/examples/miniapps/matrix-octos/manifest.json new file mode 100644 index 00000000..c433d335 --- /dev/null +++ b/examples/miniapps/matrix-octos/manifest.json @@ -0,0 +1,18 @@ +{ + "capabilities": [ + "matrix.profile", + "octos.turn.start", + "octos.turn.interrupt" + ], + "compute": { + "instruction_budget": 4000000, + "memory_bytes": 33554432 + }, + "id": "matrix-octos", + "integrity": { + "bundle_blake3": "2aa5bbc0ce2203b339ca3a4265e441279ac1d48c73181b79ac8def2d683fb451" + }, + "name": "Matrix + Octos", + "schema": 1, + "version": "1.0.0" +} diff --git a/examples/miniapps/matrix-octos/page.card b/examples/miniapps/matrix-octos/page.card new file mode 100644 index 00000000..fe367155 --- /dev/null +++ b/examples/miniapps/matrix-octos/page.card @@ -0,0 +1,22 @@ +# level: L0 +theme light +state profile {shape: record} +state answer {shape: record} +state prompt {shape: text, initial: "Say hello in one short sentence."} +state expanded {shape: bool, initial: false} +event refresh {expanded: toggle} +event typing {prompt: set($value)} +event ask {expanded: set(true)} +copy title {class: vocabulary, en: "Matrix + Octos"} +copy refresh {class: vocabulary, en: "Read my Matrix profile"} +copy ask {class: vocabulary, en: "Ask Octos"} +copy prompt {class: vocabulary, en: "Message for Octos"} +view root Surface { + TextTitle(text: copy.title) + TextBody(text: profile.data.display_name) + TextCaption(text: profile.data.user_id) + Chip(text: copy.refresh, on_tap: refresh) + Field(text: prompt, placeholder: copy.prompt, on_change: typing, on_commit: ask) + Chip(text: copy.ask, on_tap: ask) + TextBody(text: answer.data.text) +} diff --git a/examples/miniapps/matrix-octos/page.data.json b/examples/miniapps/matrix-octos/page.data.json new file mode 100644 index 00000000..fc768231 --- /dev/null +++ b/examples/miniapps/matrix-octos/page.data.json @@ -0,0 +1 @@ +{"profile":{"data":{"display_name":"Press the profile button","user_id":""}},"answer":{"data":{"text":""}}} diff --git a/src/app.rs b/src/app.rs index c26c64a4..3495321a 100644 --- a/src/app.rs +++ b/src/app.rs @@ -27,6 +27,7 @@ use crate::shared::file_upload_modal::{FileUploadModalWidgetRefExt, FileUploadMo #[cfg(feature = "agent_chat")] use crate::agent_chat::ops::ui::{AgentOpsAction, AgentOpsPanelWidgetRefExt}; use crate::moments::ui::{MomentsAction, MomentsPanelWidgetRefExt}; +use crate::octoscript_apps::{MiniAppsAction, MiniAppsPanelWidgetRefExt}; use crate::article_app::{ArticleAction, ArticlePanelWidgetRefExt}; use crate::mini_app::{MiniAppAction, MiniAppPanelWidgetRefExt}; use crate::forwarding::{ForwardAction, ForwardPanelWidgetRefExt}; @@ -131,6 +132,7 @@ mod embedded_content { } article_app_modal := Modal {can_dismiss: false content := ArticlePanel {}} + octoscript_apps_modal := Modal {can_dismiss: false content := MiniAppsPanel {}} mini_app_modal := Modal { can_dismiss: false content := MiniAppPanel {} @@ -373,6 +375,9 @@ impl MatchEvent for App { // When not yet logged in, the login_screen widget handles displaying the failure modal. if let Some(LoginAction::LoginFailure(_)) = action.downcast_ref() { crate::article_app::invalidate_sessions(); + crate::octoscript_apps::invalidate_sessions(); + let mini_modal=self.ui.modal(cx,ids!(octoscript_apps_modal)); + self.ui.mini_apps_panel(cx,ids!(octoscript_apps_modal.content)).action(cx,mini_modal,&MiniAppsAction::Close); let modal = self.ui.modal(cx, ids!(article_app_modal)); self.ui.article_panel(cx, ids!(article_app_modal.content)).action(cx, modal, &ArticleAction::Close); self.article_window_host(cx).close(cx); @@ -436,6 +441,11 @@ impl MatchEvent for App { } continue; } + if let Some(action) = action.downcast_ref::() { + let modal=self.ui.modal(cx,ids!(octoscript_apps_modal)); + self.ui.mini_apps_panel(cx,ids!(octoscript_apps_modal.content)).action(cx,modal,action); + continue; + } if let Some(action) = action.downcast_ref::() { let modal = self.ui.modal(cx, ids!(mini_app_modal)); self.ui.mini_app_panel(cx, ids!(mini_app_modal.content)).action(cx, modal, action); @@ -817,6 +827,8 @@ impl App { let modal = self.ui.modal(cx, ids!(agent_ops_modal)); self.ui.agent_ops_panel(cx, ids!(agent_ops_modal.content)).action(cx, modal, &AgentOpsAction::Close); } + let mini_modal=self.ui.modal(cx,ids!(octoscript_apps_modal)); + self.ui.mini_apps_panel(cx,ids!(octoscript_apps_modal.content)).action(cx,mini_modal,&MiniAppsAction::Close); let modal = self.ui.modal(cx, ids!(article_app_modal)); self.ui.article_panel(cx, ids!(article_app_modal.content)).action(cx, modal, &ArticleAction::Close); self.article_window_host(cx).close(cx); @@ -889,6 +901,7 @@ pub fn register_widgets(vm: &mut ScriptVm) { crate::shared::script_mod(vm); crate::mini_app::script_mod(vm); crate::article_app::script_mod(vm); + crate::octoscript_apps::script_mod(vm); crate::forwarding::script_mod(vm); #[cfg(feature = "tsp")] @@ -934,6 +947,15 @@ impl AppMain for App { } fn handle_event(&mut self, cx: &mut Cx, event: &Event) { + // A running mini app owns Back before the room/navigation widgets + // behind its modal. Close synchronously so a hosting shell sees that + // the navigation event was consumed by Rinx. + let mini_modal = self.ui.modal(cx, ids!(octoscript_apps_modal)); + if mini_modal.is_open() && event.back_pressed() { + self.ui.mini_apps_panel(cx, ids!(octoscript_apps_modal.content)) + .action(cx, mini_modal, &MiniAppsAction::Close); + return; + } if let Event::LiveEdit = event { self.app_state.app_prefs.broadcast_all(cx); } diff --git a/src/home/home_screen.rs b/src/home/home_screen.rs index fa208b15..e323b5b4 100644 --- a/src/home/home_screen.rs +++ b/src/home/home_screen.rs @@ -1075,6 +1075,7 @@ impl HomeScreen { current_screen.close_thread_timeline(cx); app_state.selected_room = None; stack_nav.pop_to_root(cx); + log!("Rinx navigation: returned to chat list"); } } self.view.redraw(cx); diff --git a/src/home/mobile.rs b/src/home/mobile.rs index a8aec01a..78ac853c 100644 --- a/src/home/mobile.rs +++ b/src/home/mobile.rs @@ -165,6 +165,8 @@ script_mod! { discover := ScrollYView { width: Fill height: Fill flow: Down spacing: 8 mod.widgets.MobileSection { + discover_mini_apps := mod.widgets.MobileRow {title.text: "Mini apps" icon.draw_icon.svg: ICON_ADD_ATTACHMENT} + mod.widgets.MobileDivider {} discover_article := mod.widgets.MobileRow {title.text: #(crate::i18n::tr("Article editor")) title.i18n_text: "Article editor" icon.draw_icon.svg: ICON_ADD_ATTACHMENT} mod.widgets.MobileDivider {} discover_moments := mod.widgets.MobileRow {title.text: #(crate::i18n::tr("Moments")) title.i18n_text: "Moments" icon.draw_icon.svg: ICON_GLOBE} @@ -489,6 +491,7 @@ impl Widget for MobileHub { if self.view.button(cx, ids!(title_bar.controls.left)).clicked(actions) { self.back(cx); } + if self.view.navigation_bar_button(cx,ids!(discover_mini_apps)).clicked(actions){cx.action(crate::octoscript_apps::MiniAppsAction::Open);} if self.view.navigation_bar_button(cx, ids!(discover_article)).clicked(actions) { cx.action(crate::article_app::ArticleAction::Open); } if self.view.navigation_bar_button(cx, ids!(discover_moments)).clicked(actions) { cx.action(crate::moments::ui::MomentsAction::Open {author: None}); diff --git a/src/home/navigation_tab_bar.rs b/src/home/navigation_tab_bar.rs index 5fa6b1a4..147d7f1d 100644 --- a/src/home/navigation_tab_bar.rs +++ b/src/home/navigation_tab_bar.rs @@ -287,6 +287,10 @@ script_mod! { tooltip_text: "Moments" icon.draw_icon.svg: ICON_GLOBE } + octoscript_apps_button := mod.widgets.NavigationTabButton { + tooltip_text: "Mini apps" + icon.draw_icon.svg: ICON_GLOBE + } article_editor_button := mod.widgets.NavigationTabButton { tooltip_text: #(crate::i18n::tr("Article editor")) icon.draw_icon.svg: ICON_EDIT @@ -667,6 +671,7 @@ impl Widget for NavigationTabBar { if self.view.navigation_bar_button(cx, ids!(moments_button)).clicked(actions) { cx.action(crate::moments::ui::MomentsAction::Open {author: None}); } + if self.view.navigation_bar_button(cx,ids!(octoscript_apps_button)).clicked(actions) {cx.action(crate::octoscript_apps::MiniAppsAction::Open);} if self.view.navigation_bar_button(cx, ids!(article_editor_button)).clicked(actions) { cx.action(crate::article_app::ArticleAction::Open); } diff --git a/src/lib.rs b/src/lib.rs index b8b27f1f..75e94ec7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -63,6 +63,7 @@ pub mod block_user_modal; /// Shared UI components. pub mod shared; pub mod mini_app; +pub mod octoscript_apps; pub mod article_app; pub mod forwarding; pub mod moments; diff --git a/src/octoscript_apps/matrix/account.rs b/src/octoscript_apps/matrix/account.rs new file mode 100644 index 00000000..4a1065b2 --- /dev/null +++ b/src/octoscript_apps/matrix/account.rs @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: MIT +// Adapted from project-robius/robrix src/a2app/matrix/account.rs +// Source revision: d4d39612fdee574a0f6a33480a19868f1ec85644 +//! Account-scoped services: the user's own identity and settings. + +use matrix_sdk::ruma::OwnedUserId; +use matrix_sdk::ruma::api::client::discovery::get_authorization_server_metadata::v1::{ + AccountManagementAction, AccountManagementActionData, +}; +use matrix_sdk::ruma::api::client::profile::{AvatarUrl, DisplayName}; + +use super::rooms::room_name; +use super::policy::{current_user_id, get_client}; +use crate::sliding_sync::{get_blocked_users, is_user_blocked}; + +pub(super) async fn user_profile(user_id: OwnedUserId) -> Result { + let client = get_client().ok_or("not logged in")?; + super::policy::ensure_server_output(client.homeserver().as_str())?; + let profile = super::policy::audit_server_operation( + client.homeserver().as_str(), + client.account().fetch_user_profile_of(&user_id), + ) + .await + .map_err(|e| format!("couldn't fetch the profile: {e}"))?; + let display_name = profile + .get_static::() + .ok() + .flatten() + .unwrap_or_else(|| user_id.localpart().to_string()); + Ok(serde_json::json!({ + "user_id": user_id, + "display_name": display_name, + "has_avatar": profile.get_static::().ok().flatten().is_some(), + "ignored": is_user_blocked(&user_id), + }) + .to_string()) +} + +pub(super) async fn dm_find(user_id: OwnedUserId) -> Result { + let client = get_client().ok_or("not logged in")?; + let Some(room) = client.get_dm_room(&user_id) else { + return Ok(serde_json::json!({ "room_id": null, "name": null }).to_string()); + }; + super::policy::ensure_room_access(room.room_id().as_str(), super::policy::RoomAccess::Read)?; + Ok(serde_json::json!({ + "room_id": room.room_id(), + "name": room_name(&room).await, + }) + .to_string()) +} + +pub(super) async fn device() -> Result { + let client = get_client().ok_or("not logged in")?; + let device_id = client.device_id().ok_or("not logged in")?.to_owned(); + let device = client + .encryption() + .get_own_device() + .await + .map_err(|e| format!("couldn't load this device: {e}"))?; + Ok(serde_json::json!({ + "device_id": device_id, + "name": device.as_ref().and_then(|d| d.display_name()), + "verified": device.as_ref().is_some_and(|d| d.is_verified()), + }) + .to_string()) +} + +pub(super) async fn info() -> Result { + let client = get_client().ok_or("not logged in")?; + let user_id = current_user_id().ok_or("not logged in")?; + // Only homeservers on OAuth have an account management page. + let account_management_url = match client.oauth().cached_server_metadata().await { + Ok(md) if md.is_account_management_action_supported(&AccountManagementAction::Profile) => { + md.account_management_url_with_action(AccountManagementActionData::Profile) + } + Ok(md) => md.account_management_uri, + Err(_) => None, + }; + Ok(serde_json::json!({ + "user_id": user_id, + "homeserver": client.homeserver().to_string(), + "account_management_url": account_management_url.map(|u| u.to_string()), + }) + .to_string()) +} + +pub(super) async fn ignored_users() -> Result { + if get_client().is_none() { + return Err("not logged in".to_string()); + } + // The SDK doesn't maintain the ignored-user list in its store, so `sliding_sync` + // keeps the authoritative set. Reading the raw account data here would let this + // service disagree with Settings and with `user_profile()` above. + Ok(serde_json::json!({ "users": get_blocked_users() }).to_string()) +} diff --git a/src/octoscript_apps/matrix/membership.rs b/src/octoscript_apps/matrix/membership.rs new file mode 100644 index 00000000..50c0acf8 --- /dev/null +++ b/src/octoscript_apps/matrix/membership.rs @@ -0,0 +1,133 @@ +// SPDX-License-Identifier: MIT +// Adapted from project-robius/robrix src/a2app/matrix/membership.rs +// Source revision: d4d39612fdee574a0f6a33480a19868f1ec85644 +//! Membership changes an app can ask for: invites, joins, invite answers +//! and starting DMs. + +use matrix_sdk::RoomState; +use matrix_sdk::ruma::{OwnedRoomId, OwnedRoomOrAliasId, OwnedServerName, OwnedUserId}; + +use super::policy::get_client; +use super::policy::RoomAccess; +use super::policy::ensure_room_access; + +pub(super) async fn invite(room_id: OwnedRoomId, user_id: OwnedUserId) -> Result { + ensure_room_access(room_id.as_str(), RoomAccess::Write)?; + let client = get_client().ok_or("not logged in")?; + let room = client.get_room(&room_id).ok_or("room not found")?; + super::policy::ensure_server_output(client.homeserver().as_str())?; + super::policy::commit_sensitive_target( + room_id.as_str(), + &serde_json::json!({ "user_id": user_id }), + )?; + super::policy::audit_server_operation( + client.homeserver().as_str(), + room.invite_user_by_id(&user_id), + ) + .await + .map_err(|e| format!("couldn't invite {user_id}: {e}"))?; + Ok(String::from("{}")) +} + +pub(super) async fn join( + room: OwnedRoomOrAliasId, + mut via: Vec, +) -> Result { + use matrix_sdk::ruma::api::error::ErrorKind; + let client = get_client().ok_or("not logged in")?; + let target = super::rooms::resolve_room_id(&client, &room, &mut via).await?; + ensure_room_access(target.as_str(), RoomAccess::Write)?; + // Resolve once, then use the checked id: an alias changing during the + // request cannot redirect a permitted join into a protected room. + let room = OwnedRoomOrAliasId::from(target); + super::policy::ensure_server_output(client.homeserver().as_str())?; + super::policy::commit_sensitive_target( + room.as_str(), + &serde_json::json!({ "operation": "join", "room_id": room, "via": via }), + )?; + let (joined, knocked) = + super::policy::audit_server_operation(client.homeserver().as_str(), async { + match client.join_room_by_id_or_alias(&room, &via).await { + Ok(joined) => Ok((joined, false)), + // An invite-only room refuses the join, so knocking is the next best ask. + Err(e) if matches!(e.client_api_error_kind(), Some(ErrorKind::Forbidden)) => { + ensure_room_access(room.as_str(), RoomAccess::Write)?; + super::policy::ensure_server_output(client.homeserver().as_str())?; + super::policy::commit_sensitive_target( + room.as_str(), + &serde_json::json!({ "operation": "knock", "room_id": room, "via": via }), + )?; + let knocked = super::policy::audit_server_operation( + client.homeserver().as_str(), + client.knock(room, None, via), + ) + .await + .map_err(|e| format!("couldn't knock on the room: {e}"))?; + Ok((knocked, true)) + } + Err(e) => Err(format!("couldn't join the room: {e}")), + } + }) + .await?; + Ok(serde_json::json!({ + "room_id": joined.room_id(), + "joined": !knocked, + "knocked": knocked, + }) + .to_string()) +} + +pub(super) async fn invite_respond(room_id: OwnedRoomId, accept: bool) -> Result { + ensure_room_access(room_id.as_str(), RoomAccess::Write)?; + let client = get_client().ok_or("not logged in")?; + let room = client.get_room(&room_id).ok_or("room not found")?; + if room.state() != RoomState::Invited { + return Err("there's no pending invite for that room".into()); + } + super::policy::ensure_server_output(client.homeserver().as_str())?; + super::policy::commit_sensitive_target( + room_id.as_str(), + &serde_json::json!({ "accept": accept }), + )?; + let result = if accept { + super::policy::audit_server_operation(client.homeserver().as_str(), room.join()).await + } else { + super::policy::audit_server_operation(client.homeserver().as_str(), room.leave()).await + }; + result.map_err(|e| { + format!( + "couldn't {} the invite: {e}", + if accept { "accept" } else { "decline" } + ) + })?; + Ok(String::from("{}")) +} + +pub(super) async fn dm_open(user_id: OwnedUserId) -> Result { + let client = get_client().ok_or("not logged in")?; + let (room, created) = match client.get_dm_room(&user_id) { + Some(room) => { + ensure_room_access(room.room_id().as_str(), RoomAccess::Read)?; + ensure_room_access(room.room_id().as_str(), RoomAccess::Write)?; + (room, false) + } + None => { + if !super::policy::global_room_access_allowed("", RoomAccess::Write) { + return Err(super::policy::ROOM_ACCESS_DENIED.to_string()); + } + super::policy::ensure_server_output(client.homeserver().as_str())?; + super::policy::commit_sensitive_target( + "host", + &serde_json::json!({ "create_dm_with": user_id }), + )?; + let room = super::policy::audit_server_operation( + client.homeserver().as_str(), + client.create_dm(&user_id), + ) + .await + .map_err(|e| format!("couldn't start a chat with {user_id}: {e}"))?; + (room, true) + } + }; + Ok(serde_json::json!({ "room_id": room.room_id(), "created": created }).to_string()) +} diff --git a/src/octoscript_apps/matrix/mod.rs b/src/octoscript_apps/matrix/mod.rs new file mode 100644 index 00000000..2eead897 --- /dev/null +++ b/src/octoscript_apps/matrix/mod.rs @@ -0,0 +1,1070 @@ +// SPDX-License-Identifier: MIT +//! A2App-compatible Matrix operations using the active Rinx SDK session. +use std::collections::HashSet; +use matrix_sdk::RoomState; +use matrix_sdk::ruma::{OwnedEventId, OwnedRoomId, OwnedRoomOrAliasId, OwnedServerName, OwnedUserId}; +use rinx_miniapp_core::{ + Lease, + matrix::{MatrixServiceCall, SearchScope, RoomFlag}, +}; +use policy::{get_client, current_user_id, RoomAccess}; +mod account; +mod membership; +mod room; +mod rooms; +mod send; +mod spaces; +mod policy; +type Reply = (); +// SDK implementation adapted from A2App revision d4d39612fdee574a0f6a33480a19868f1ec85644 +pub enum A2AppMatrixRequest { + RoomInfo { + room_id: OwnedRoomId, + reply: Reply, + }, + ReadMessages { + room_id: OwnedRoomId, + limit: u32, + reply: Reply, + }, + SendMessage { + room_id: OwnedRoomId, + body: String, + reply: Reply, + }, + Profile { + reply: Reply, + }, + Members { + room_id: OwnedRoomId, + limit: u32, + reply: Reply, + }, + PinnedEvents { + room_id: OwnedRoomId, + reply: Reply, + }, + Threads { + room_id: OwnedRoomId, + limit: u32, + reply: Reply, + }, + RoomsList { + reply: Reply, + }, + Search { + rooms: SearchRooms, + query: String, + limit: u32, + server: bool, + reply: Reply, + }, + + // --- room --- + ThreadReplies { + room_id: OwnedRoomId, + event_id: OwnedEventId, + limit: u32, + reply: Reply, + }, + OlderMessages { + room_id: OwnedRoomId, + before: Option, + limit: u32, + reply: Reply, + }, + Event { + room_id: OwnedRoomId, + event_id: OwnedEventId, + reply: Reply, + }, + ReadReceipts { + room_id: OwnedRoomId, + user_id: Option, + reply: Reply, + }, + Unread { + room_id: OwnedRoomId, + reply: Reply, + }, + PowerLevels { + room_id: OwnedRoomId, + reply: Reply, + }, + Permalink { + room_id: OwnedRoomId, + event_id: Option, + use_matrix_scheme: bool, + reply: Reply, + }, + Successor { + room_id: OwnedRoomId, + reply: Reply, + }, + + // --- rooms --- + RoomsSearch { + query: String, + limit: u32, + reply: Reply, + }, + Invites { + reply: Reply, + }, + RoomPreview { + room: OwnedRoomOrAliasId, + via: Vec, + reply: Reply, + }, + RoomsInfo { + room_id: OwnedRoomId, + reply: Reply, + }, + RoomsMessages { + room_id: OwnedRoomId, + limit: u32, + reply: Reply, + }, + + // --- spaces --- + Spaces { + reply: Reply, + }, + SpaceInfo { + space_id: OwnedRoomId, + reply: Reply, + }, + SpaceRooms { + space_id: OwnedRoomId, + reply: Reply, + }, + + // --- account --- + UserProfile { + user_id: OwnedUserId, + reply: Reply, + }, + DmFind { + user_id: OwnedUserId, + reply: Reply, + }, + Device { + reply: Reply, + }, + AccountInfo { + reply: Reply, + }, + IgnoredUsers { + reply: Reply, + }, + + // --- send --- + Reply { + room_id: OwnedRoomId, + event_id: OwnedEventId, + body: String, + in_thread: bool, + reply: Reply, + }, + React { + room_id: OwnedRoomId, + event_id: OwnedEventId, + key: String, + reply: Reply, + }, + Typing { + room_id: OwnedRoomId, + typing: bool, + reply: Reply, + }, + ReadReceipt { + room_id: OwnedRoomId, + event_id: Option, + reply: Reply, + }, + Pin { + room_id: OwnedRoomId, + event_id: OwnedEventId, + pinned: bool, + reply: Reply, + }, + RoomFlag { + room_id: OwnedRoomId, + flag: RoomFlag, + on: bool, + reply: Reply, + }, + + // --- membership --- + Invite { + room_id: OwnedRoomId, + user_id: OwnedUserId, + reply: Reply, + }, + Join { + room: OwnedRoomOrAliasId, + via: Vec, + reply: Reply, + }, + InviteRespond { + room_id: OwnedRoomId, + accept: bool, + reply: Reply, + }, + DmOpen { + user_id: OwnedUserId, + reply: Reply, + }, +} + +#[derive(Debug)] +pub enum SearchRooms { + One(OwnedRoomId), + AllJoined, + Some(Vec), +} +pub fn request_for( + call: MatrixServiceCall, + room: Option, + reply: Reply, +) -> Result { + Ok(match (call, room) { + (MatrixServiceCall::Profile, _) => A2AppMatrixRequest::Profile { reply }, + (MatrixServiceCall::RoomsList, _) => A2AppMatrixRequest::RoomsList { reply }, + ( + MatrixServiceCall::Search { + query, + scope: SearchScope::AllJoined, + limit, + server, + }, + _, + ) => A2AppMatrixRequest::Search { + rooms: SearchRooms::AllJoined, + query, + limit, + server, + reply, + }, + ( + MatrixServiceCall::Search { + query, + scope: SearchScope::Rooms(ids), + limit, + server, + }, + _, + ) => { + let ids: Vec = ids + .iter() + .filter_map(|id| OwnedRoomId::try_from(id.as_str()).ok()) + .collect(); + if ids.is_empty() { + return Err("no valid room ids"); + } + A2AppMatrixRequest::Search { + rooms: SearchRooms::Some(ids), + query, + limit, + server, + reply, + } + } + ( + MatrixServiceCall::Search { + query, + scope: SearchScope::Attached, + limit, + server, + }, + Some(room_id), + ) => A2AppMatrixRequest::Search { + rooms: SearchRooms::One(room_id), + query, + limit, + server, + reply, + }, + // The room-free rooms, spaces and account services sit above the + // no-room guard on purpose; `parse` has already checked the id sigils. + (MatrixServiceCall::RoomsSearch { query, limit }, _) => A2AppMatrixRequest::RoomsSearch { + query, + limit, + reply, + }, + (MatrixServiceCall::Invites, _) => A2AppMatrixRequest::Invites { reply }, + (MatrixServiceCall::RoomPreview { room, via }, _) => { + let room = OwnedRoomOrAliasId::try_from(room.as_str()) + .map_err(|_| "invalid room id or alias")?; + let via = via + .iter() + .filter_map(|s| OwnedServerName::try_from(s.as_str()).ok()) + .collect(); + A2AppMatrixRequest::RoomPreview { room, via, reply } + } + (MatrixServiceCall::RoomsInfo { room_id }, _) => A2AppMatrixRequest::RoomsInfo { + room_id: OwnedRoomId::try_from(room_id.as_str()).map_err(|_| "invalid room id")?, + reply, + }, + (MatrixServiceCall::RoomsMessages { room_id, limit }, _) => { + A2AppMatrixRequest::RoomsMessages { + room_id: OwnedRoomId::try_from(room_id.as_str()).map_err(|_| "invalid room id")?, + limit, + reply, + } + } + (MatrixServiceCall::Spaces, _) => A2AppMatrixRequest::Spaces { reply }, + (MatrixServiceCall::SpaceInfo { space_id }, _) => A2AppMatrixRequest::SpaceInfo { + space_id: OwnedRoomId::try_from(space_id.as_str()).map_err(|_| "invalid space id")?, + reply, + }, + (MatrixServiceCall::SpaceRooms { space_id }, _) => A2AppMatrixRequest::SpaceRooms { + space_id: OwnedRoomId::try_from(space_id.as_str()).map_err(|_| "invalid space id")?, + reply, + }, + (MatrixServiceCall::UserProfile { user_id }, _) => A2AppMatrixRequest::UserProfile { + user_id: OwnedUserId::try_from(user_id.as_str()).map_err(|_| "invalid user id")?, + reply, + }, + (MatrixServiceCall::DmFind { user_id }, _) => A2AppMatrixRequest::DmFind { + user_id: OwnedUserId::try_from(user_id.as_str()).map_err(|_| "invalid user id")?, + reply, + }, + (MatrixServiceCall::Device, _) => A2AppMatrixRequest::Device { reply }, + (MatrixServiceCall::AccountInfo, _) => A2AppMatrixRequest::AccountInfo { reply }, + (MatrixServiceCall::IgnoredUsers, _) => A2AppMatrixRequest::IgnoredUsers { reply }, + (MatrixServiceCall::RoomInfo, Some(room_id)) => { + A2AppMatrixRequest::RoomInfo { room_id, reply } + } + (MatrixServiceCall::ReadMessages { limit }, Some(room_id)) => { + A2AppMatrixRequest::ReadMessages { + room_id, + limit, + reply, + } + } + (MatrixServiceCall::SendMessage { body }, Some(room_id)) => { + A2AppMatrixRequest::SendMessage { + room_id, + body, + reply, + } + } + (MatrixServiceCall::Members { limit }, Some(room_id)) => A2AppMatrixRequest::Members { + room_id, + limit, + reply, + }, + (MatrixServiceCall::PinnedEvents, Some(room_id)) => { + A2AppMatrixRequest::PinnedEvents { room_id, reply } + } + (MatrixServiceCall::Threads { limit }, Some(room_id)) => A2AppMatrixRequest::Threads { + room_id, + limit, + reply, + }, + + // --- room --- + (MatrixServiceCall::ThreadReplies { event_id, limit }, Some(room_id)) => { + let Ok(event_id) = OwnedEventId::try_from(event_id.as_str()) else { + return Err("not a valid event id"); + }; + A2AppMatrixRequest::ThreadReplies { + room_id, + event_id, + limit, + reply, + } + } + (MatrixServiceCall::OlderMessages { before, limit }, Some(room_id)) => { + let Ok(before) = before + .map(|id| OwnedEventId::try_from(id.as_str())) + .transpose() + else { + return Err("not a valid event id"); + }; + A2AppMatrixRequest::OlderMessages { + room_id, + before, + limit, + reply, + } + } + (MatrixServiceCall::Event { event_id }, Some(room_id)) => { + let Ok(event_id) = OwnedEventId::try_from(event_id.as_str()) else { + return Err("not a valid event id"); + }; + A2AppMatrixRequest::Event { + room_id, + event_id, + reply, + } + } + (MatrixServiceCall::ReadReceipts { user_id }, Some(room_id)) => { + let Ok(user_id) = user_id + .map(|id| OwnedUserId::try_from(id.as_str())) + .transpose() + else { + return Err("not a valid user id"); + }; + A2AppMatrixRequest::ReadReceipts { + room_id, + user_id, + reply, + } + } + (MatrixServiceCall::Unread, Some(room_id)) => A2AppMatrixRequest::Unread { room_id, reply }, + (MatrixServiceCall::PowerLevels, Some(room_id)) => { + A2AppMatrixRequest::PowerLevels { room_id, reply } + } + ( + MatrixServiceCall::Permalink { + event_id, + use_matrix_scheme, + }, + Some(room_id), + ) => { + let Ok(event_id) = event_id + .map(|id| OwnedEventId::try_from(id.as_str())) + .transpose() + else { + return Err("not a valid event id"); + }; + A2AppMatrixRequest::Permalink { + room_id, + event_id, + use_matrix_scheme, + reply, + } + } + (MatrixServiceCall::Successor, Some(room_id)) => { + A2AppMatrixRequest::Successor { room_id, reply } + } + + // --- rooms --- + + // --- spaces --- + + // --- account --- + + // --- send --- + ( + MatrixServiceCall::Reply { + event_id, + body, + in_thread, + }, + Some(room_id), + ) => A2AppMatrixRequest::Reply { + room_id, + event_id: OwnedEventId::try_from(event_id).map_err(|_| "invalid event_id")?, + body, + in_thread, + reply, + }, + (MatrixServiceCall::React { event_id, key }, Some(room_id)) => A2AppMatrixRequest::React { + room_id, + event_id: OwnedEventId::try_from(event_id).map_err(|_| "invalid event_id")?, + key, + reply, + }, + (MatrixServiceCall::Typing { typing }, Some(room_id)) => A2AppMatrixRequest::Typing { + room_id, + typing, + reply, + }, + (MatrixServiceCall::ReadReceipt { event_id }, Some(room_id)) => { + A2AppMatrixRequest::ReadReceipt { + room_id, + event_id: event_id + .map(OwnedEventId::try_from) + .transpose() + .map_err(|_| "invalid event_id")?, + reply, + } + } + (MatrixServiceCall::Pin { event_id, pinned }, Some(room_id)) => A2AppMatrixRequest::Pin { + room_id, + event_id: OwnedEventId::try_from(event_id).map_err(|_| "invalid event_id")?, + pinned, + reply, + }, + (MatrixServiceCall::RoomFlag { flag, on }, Some(room_id)) => A2AppMatrixRequest::RoomFlag { + room_id, + flag, + on, + reply, + }, + (MatrixServiceCall::RoomsSend { room_id, body }, _) => A2AppMatrixRequest::SendMessage { + room_id: OwnedRoomId::try_from(room_id).map_err(|_| "invalid room_id")?, + body, + reply, + }, + + // --- membership --- + (MatrixServiceCall::Invite { user_id }, Some(room_id)) => A2AppMatrixRequest::Invite { + room_id, + user_id: OwnedUserId::try_from(user_id).map_err(|_| "invalid user_id")?, + reply, + }, + (MatrixServiceCall::Join { room, via }, _) => A2AppMatrixRequest::Join { + room: OwnedRoomOrAliasId::try_from(room).map_err(|_| "invalid room id or alias")?, + via: via + .into_iter() + .map(OwnedServerName::try_from) + .collect::>() + .map_err(|_| "invalid via server name")?, + reply, + }, + (MatrixServiceCall::InviteRespond { room_id, accept }, _) => { + A2AppMatrixRequest::InviteRespond { + room_id: OwnedRoomId::try_from(room_id).map_err(|_| "invalid room_id")?, + accept, + reply, + } + } + (MatrixServiceCall::DmOpen { user_id }, _) => A2AppMatrixRequest::DmOpen { + user_id: OwnedUserId::try_from(user_id).map_err(|_| "invalid user_id")?, + reply, + }, + + (_, None) => { + return Err("this mini-app is not attached to a room"); + } + }) +} + +/// Cuts a body to `max` chars on a char boundary; a byte truncate could +/// split a multi-byte char and panic. +pub(crate) fn clip_chars(s: &mut String, max: usize) { + if let Some((idx, _)) = s.char_indices().nth(max) { + s.truncate(idx); + } +} + +pub async fn execute( + client: matrix_sdk::Client, + lease: Lease, + service: String, + args: serde_json::Value, +) -> Result { + let account = client.user_id().ok_or("Not logged in")?.to_string(); + let target = args + .get("room_id") + .or_else(|| args.get("space_id")) + .and_then(|v| v.as_str()); + lease.authorize(&account, &service, target)?; + let room = lease + .identity() + .room + .as_deref() + .map(OwnedRoomId::try_from) + .transpose() + .map_err(|_| "Invalid attached room")?; + let call = rinx_miniapp_core::matrix::parse(&service, &args, room.is_some())?; + if room + .as_ref() + .is_some_and(|id| !lease.permits_room(id.as_str())) + { + return Err("Attached room was not granted".into()); + } + let request = request_for(call, room, ())?; + policy::with_context(client, lease, service, async move { + let (_, result) = match request { + A2AppMatrixRequest::RoomInfo { room_id, reply } => (reply, room::info(room_id).await), + A2AppMatrixRequest::ReadMessages { + room_id, + limit, + reply, + } => (reply, room::read_messages(room_id, limit, false).await), + A2AppMatrixRequest::SendMessage { + room_id, + body, + reply, + } => (reply, send::message(room_id, body).await), + A2AppMatrixRequest::Members { + room_id, + limit, + reply, + } => { + let result: Result = async { + use matrix_sdk::RoomMemberships; + let client = get_client().ok_or("not logged in")?; + let room = client.get_room(&room_id).ok_or("room not found")?; + // A full /members sync on a big room can take tens of + // seconds, so serve from the store unless it's too sparse + // to even fill the requested page. + let joined_count = room.joined_members_count(); + let mut members = room + .members_no_sync(RoomMemberships::JOIN) + .await + .unwrap_or_default(); + if (members.len() as u64) < joined_count.min(limit as u64) { + members = room + .members(RoomMemberships::JOIN) + .await + .map_err(|e| format!("couldn't load members: {e}"))?; + } + let count = (members.len() as u64).max(joined_count); + let out: Vec = members + .iter() + .take(limit as usize) + .map(|m| { + use matrix_sdk::ruma::events::room::power_levels::UserPowerLevel; + // A room creator's power is "infinite" from room v12 on. + let power: i64 = match m.power_level() { + UserPowerLevel::Int(int) => int.into(), + _ => i64::MAX, + }; + serde_json::json!({ + "name": m.name(), + "user_id": m.user_id().to_string(), + "power": power, + }) + }) + .collect(); + Ok(serde_json::json!({ "count": count, "members": out }).to_string()) + } + .await; + (reply, result) + } + A2AppMatrixRequest::PinnedEvents { room_id, reply } => { + let result: Result = async { + use matrix_sdk::ruma::events::{ + AnySyncMessageLikeEvent, AnySyncTimelineEvent, SyncMessageLikeEvent, + }; + let client = get_client().ok_or("not logged in")?; + let room = client.get_room(&room_id).ok_or("room not found")?; + let pinned_ids = room.pinned_event_ids().unwrap_or_default(); + let mut out: Vec = Vec::new(); + // Serve each pin from the event cache/store; only misses go + // to the network, and those run concurrently. + let cache = client.event_cache().room(&room_id).await.ok(); + let cache_ref = cache.as_ref().map(|(c, _)| c); + let room_ref = &room; + let fetched = futures_util::future::join_all(pinned_ids.iter().take(10).map( + |event_id| async move { + if let Some(c) = cache_ref { + if let Ok(Some(event)) = c.find_event(event_id).await { + return Some(event); + } + } + policy::audit_server_operation( + room_ref.client().homeserver().as_str(), + room_ref.event(event_id, None), + ) + .await + .ok() + }, + )) + .await; + for event in fetched.into_iter().flatten() { + let Ok(AnySyncTimelineEvent::MessageLike( + AnySyncMessageLikeEvent::RoomMessage(SyncMessageLikeEvent::Original( + msg, + )), + )) = event.raw().deserialize() + else { + continue; + }; + let mut body = msg.content.body().to_string(); + clip_chars(&mut body, 300); + out.push(serde_json::json!({ + "sender": msg.sender.localpart(), + "sender_id": msg.sender, + "event_id": msg.event_id, + "body": body, + })); + } + Ok(serde_json::json!({ "pinned": out }).to_string()) + } + .await; + (reply, result) + } + A2AppMatrixRequest::Threads { + room_id, + limit, + reply, + } => { + let result: Result = async { + use matrix_sdk::room::ListThreadsOptions; + use matrix_sdk::ruma::events::{ + AnySyncMessageLikeEvent, AnySyncTimelineEvent, SyncMessageLikeEvent, + }; + let client = get_client().ok_or("not logged in")?; + let room = client.get_room(&room_id).ok_or("room not found")?; + let opts = ListThreadsOptions::default(); + let roots = policy::audit_server_operation( + client.homeserver().as_str(), + room.list_threads(opts), + ) + .await + .map_err(|e| format!("couldn't list threads: {e}"))?; + let mut out: Vec = Vec::new(); + for event in roots.chunk.iter().take(limit as usize) { + let Ok(AnySyncTimelineEvent::MessageLike( + AnySyncMessageLikeEvent::RoomMessage(SyncMessageLikeEvent::Original( + msg, + )), + )) = event.raw().deserialize() + else { + continue; + }; + let mut body = msg.content.body().to_string(); + clip_chars(&mut body, 300); + out.push(serde_json::json!({ + "sender": msg.sender.localpart(), + "sender_id": msg.sender, + "event_id": msg.event_id, + "body": body, + })); + } + Ok(serde_json::json!({ "threads": out }).to_string()) + } + .await; + (reply, result) + } + A2AppMatrixRequest::RoomsList { reply } => (reply, rooms::joined_rooms_list().await), + A2AppMatrixRequest::Search { + rooms, + query, + limit, + server, + reply, + } => { + use matrix_sdk::ruma::events::room::message::sanitize::remove_plain_reply_fallback; + let result: Result = async { + use matrix_sdk::ruma::events::{ + AnyMessageLikeEvent, AnySyncMessageLikeEvent, AnySyncTimelineEvent, + AnyTimelineEvent, MessageLikeEvent, SyncMessageLikeEvent, + }; + let client = get_client().ok_or("not logged in")?; + let mut targets: Vec = match rooms { + SearchRooms::One(id) => vec![client.get_room(&id).ok_or("room not found")?], + SearchRooms::AllJoined => client + .joined_rooms() + .into_iter() + .filter(|r| !r.is_space()) + .collect(), + SearchRooms::Some(ids) => ids + .iter() + .filter_map(|id| client.get_room(id)) + .filter(|r| r.state() == RoomState::Joined && !r.is_space()) + .collect(), + }; + targets.retain(|room| { + policy::room_access_allowed(room.room_id().as_str(), RoomAccess::Read) + }); + let needle = query.to_lowercase(); + let mut seen: HashSet = HashSet::new(); + let mut hits: Vec<(u64, serde_json::Value)> = Vec::new(); + for room in &targets { + if !policy::room_access_allowed(room.room_id().as_str(), RoomAccess::Read) { + continue; + } + let room_name = room + .cached_display_name() + .map(|n| n.to_string()) + .unwrap_or_else(|| room.room_id().to_string()); + // What is in memory plus everything Robrix has stored + // for the room: decrypted content, no network. + let mut events = Vec::new(); + if let Ok((cache, _guard)) = client.event_cache().room(room.room_id()).await + && let Ok(cached) = cache.events().await + { + events.extend(cached); + } + if let Ok(store) = client.event_cache_store().lock().await + && let Some(store) = store.as_clean() + && let Ok(stored) = store + .get_room_events(room.room_id(), Some("m.room.message"), None) + .await + { + events.extend(stored); + } + for event in events { + let Ok(AnySyncTimelineEvent::MessageLike( + AnySyncMessageLikeEvent::RoomMessage( + SyncMessageLikeEvent::Original(msg), + ), + )) = event.raw().deserialize() + else { + continue; + }; + if !seen.insert(msg.event_id.clone()) { + continue; + } + let mut body = + remove_plain_reply_fallback(msg.content.body()).to_string(); + if !body.to_lowercase().contains(&needle) { + continue; + } + clip_chars(&mut body, 300); + let ts = u64::from(msg.origin_server_ts.0); + hits.push(( + ts, + serde_json::json!({ + "room_id": room.room_id(), + "room_name": room_name, + "event_id": msg.event_id, + "sender": msg.sender.localpart(), + "sender_id": msg.sender, + "body": body, + "ts": ts, + "source": "local", + }), + )); + } + } + let mut server_used = false; + let unencrypted: Vec = targets + .iter() + .filter(|r| !r.encryption_state().is_encrypted()) + .filter(|r| { + policy::room_access_allowed(r.room_id().as_str(), RoomAccess::Read) + }) + .map(|r| r.room_id().to_owned()) + .collect(); + if server && !unencrypted.is_empty() { + use matrix_sdk::ruma::api::client::filter::RoomEventFilter; + use matrix_sdk::ruma::api::client::search::search_events::v3::{ + Categories, Criteria, OrderBy, Request, SearchKeys, + }; + let mut criteria = Criteria::new(query.clone()); + criteria.keys = Some(vec![SearchKeys::ContentBody]); + criteria.order_by = Some(OrderBy::Recent); + let mut filter = RoomEventFilter::default(); + filter.rooms = Some(unencrypted); + criteria.filter = filter; + let mut categories = Categories::new(); + categories.room_events = Some(criteria); + // Search terms are plaintext to the homeserver even when + // their source was an encrypted room. Room output consent + // does not authorize this distinct network recipient. + policy::ensure_server_output(client.homeserver().as_str())?; + let response = policy::audit_server_operation( + client.homeserver().as_str(), + client.send(Request::new(categories)), + ) + .await + .map_err(|e| format!("server search failed: {e}"))?; + server_used = true; + for hit in response.search_categories.room_events.results { + let Some(raw) = hit.result else { continue }; + let Ok(AnyTimelineEvent::MessageLike( + AnyMessageLikeEvent::RoomMessage(MessageLikeEvent::Original(msg)), + )) = raw.deserialize() + else { + continue; + }; + if !targets.iter().any(|room| room.room_id() == msg.room_id) + || !policy::room_access_allowed( + msg.room_id.as_str(), + RoomAccess::Read, + ) + { + continue; + } + if !seen.insert(msg.event_id.clone()) { + continue; + } + let room_name = client + .get_room(&msg.room_id) + .and_then(|r| r.cached_display_name()) + .map(|n| n.to_string()) + .unwrap_or_else(|| msg.room_id.to_string()); + let mut body = + remove_plain_reply_fallback(msg.content.body()).to_string(); + clip_chars(&mut body, 300); + let ts = u64::from(msg.origin_server_ts.0); + hits.push(( + ts, + serde_json::json!({ + "room_id": msg.room_id, + "room_name": room_name, + "event_id": msg.event_id, + "sender": msg.sender.localpart(), + "sender_id": msg.sender, + "body": body, + "ts": ts, + "source": "server", + }), + )); + } + } + hits.sort_by_key(|(ts, _)| std::cmp::Reverse(*ts)); + hits.truncate(limit as usize); + let results: Vec = + hits.into_iter().map(|(_, v)| v).collect(); + Ok(serde_json::json!({ + "results": results, + "searched_rooms": targets.len(), + "server_used": server_used, + }) + .to_string()) + } + .await; + (reply, result) + } + A2AppMatrixRequest::Profile { reply } => { + let result: Result = async { + let client = get_client().ok_or("not logged in")?; + let user_id = current_user_id().ok_or("not logged in")?; + let display_name = policy::audit_server_operation( + client.homeserver().as_str(), + client.account().get_display_name(), + ) + .await + .ok() + .flatten() + .unwrap_or_else(|| user_id.localpart().to_string()); + Ok(serde_json::json!({ + "user_id": user_id.to_string(), + "display_name": display_name, + }) + .to_string()) + } + .await; + (reply, result) + } + A2AppMatrixRequest::ThreadReplies { + room_id, + event_id, + limit, + reply, + } => (reply, room::thread_replies(room_id, event_id, limit).await), + A2AppMatrixRequest::OlderMessages { + room_id, + before, + limit, + reply, + } => ( + reply, + room::older_messages(room_id, before, limit, false).await, + ), + A2AppMatrixRequest::Event { + room_id, + event_id, + reply, + } => (reply, room::event(room_id, event_id).await), + A2AppMatrixRequest::ReadReceipts { + room_id, + user_id, + reply, + } => (reply, room::read_receipts(room_id, user_id).await), + A2AppMatrixRequest::Unread { room_id, reply } => (reply, room::unread(room_id).await), + A2AppMatrixRequest::PowerLevels { room_id, reply } => { + (reply, room::power_levels(room_id).await) + } + A2AppMatrixRequest::Permalink { + room_id, + event_id, + use_matrix_scheme, + reply, + } => ( + reply, + room::permalink(room_id, event_id, use_matrix_scheme).await, + ), + A2AppMatrixRequest::Successor { room_id, reply } => { + (reply, room::successor(room_id).await) + } + + // --- rooms --- + A2AppMatrixRequest::RoomsSearch { + query, + limit, + reply, + } => (reply, rooms::search(query, limit).await), + A2AppMatrixRequest::Invites { reply } => (reply, rooms::invites().await), + A2AppMatrixRequest::RoomPreview { room, via, reply } => { + (reply, rooms::preview(room, via).await) + } + A2AppMatrixRequest::RoomsInfo { room_id, reply } => (reply, room::info(room_id).await), + A2AppMatrixRequest::RoomsMessages { + room_id, + limit, + reply, + } => (reply, room::read_messages(room_id, limit, false).await), + + // --- spaces --- + A2AppMatrixRequest::Spaces { reply } => (reply, spaces::list().await), + A2AppMatrixRequest::SpaceInfo { space_id, reply } => { + (reply, spaces::info(space_id).await) + } + A2AppMatrixRequest::SpaceRooms { space_id, reply } => { + (reply, spaces::rooms(space_id).await) + } + + // --- account --- + A2AppMatrixRequest::UserProfile { user_id, reply } => { + (reply, account::user_profile(user_id).await) + } + A2AppMatrixRequest::DmFind { user_id, reply } => { + (reply, account::dm_find(user_id).await) + } + A2AppMatrixRequest::Device { reply } => (reply, account::device().await), + A2AppMatrixRequest::AccountInfo { reply } => (reply, account::info().await), + A2AppMatrixRequest::IgnoredUsers { reply } => (reply, account::ignored_users().await), + + // --- send --- + A2AppMatrixRequest::Reply { + room_id, + event_id, + body, + in_thread, + reply, + } => (reply, send::reply(room_id, event_id, body, in_thread).await), + A2AppMatrixRequest::React { + room_id, + event_id, + key, + reply, + } => (reply, send::react(room_id, event_id, key).await), + A2AppMatrixRequest::Typing { + room_id, + typing, + reply, + } => (reply, send::typing(room_id, typing).await), + A2AppMatrixRequest::ReadReceipt { + room_id, + event_id, + reply, + } => (reply, send::read_receipt(room_id, event_id).await), + A2AppMatrixRequest::Pin { + room_id, + event_id, + pinned, + reply, + } => (reply, send::pin(room_id, event_id, pinned).await), + A2AppMatrixRequest::RoomFlag { + room_id, + flag, + on, + reply, + } => (reply, send::room_flag(room_id, flag, on).await), + + // --- membership --- + A2AppMatrixRequest::Invite { + room_id, + user_id, + reply, + } => (reply, membership::invite(room_id, user_id).await), + A2AppMatrixRequest::Join { room, via, reply } => { + (reply, membership::join(room, via).await) + } + A2AppMatrixRequest::InviteRespond { + room_id, + accept, + reply, + } => (reply, membership::invite_respond(room_id, accept).await), + A2AppMatrixRequest::DmOpen { user_id, reply } => { + (reply, membership::dm_open(user_id).await) + } + }; + policy::check()?; + let value = + serde_json::from_str(&result?).map_err(|e| format!("Invalid Matrix response: {e}"))?; + rinx_miniapp_core::bounded_reply(value) + }) + .await +} diff --git a/src/octoscript_apps/matrix/policy.rs b/src/octoscript_apps/matrix/policy.rs new file mode 100644 index 00000000..3fdb3fa8 --- /dev/null +++ b/src/octoscript_apps/matrix/policy.rs @@ -0,0 +1,141 @@ +//! Request-scoped SDK identity and explicit room grants. No global SDK lookup +//! can redirect queued work into a replacement login session. +use matrix_sdk::{Client, ruma::OwnedUserId}; +use rinx_miniapp_core::Lease; +use std::future::IntoFuture; + +pub const ROOM_ACCESS_DENIED: &str = "Mini app was not granted access to this room"; +#[derive(Clone, Copy)] +pub enum RoomAccess { + Read, + Write, +} +struct Context { + client: Client, + lease: Lease, + service: String, +} +tokio::task_local! { static CONTEXT: Context; } + +pub async fn with_context( + client: Client, + lease: Lease, + service: String, + future: impl std::future::Future, +) -> T { + CONTEXT + .scope( + Context { + client, + lease, + service, + }, + future, + ) + .await +} +pub fn check() -> Result<(), String> { + if crate::logout::logout_state_machine::is_logout_in_progress() { + return Err("Matrix session is closing".into()); + } + let account = crate::sliding_sync::current_user_id().ok_or("Not logged in")?; + CONTEXT + .try_with(|ctx| ctx.lease.check(account.as_str())) + .map_err(|_| "Missing mini-app request context")? +} +pub fn get_client() -> Option { + check().ok()?; + CONTEXT.try_with(|ctx| ctx.client.clone()).ok() +} +pub fn current_user_id() -> Option { + get_client()?.user_id().map(ToOwned::to_owned) +} + +fn writing(service: &str) -> bool { + matches!( + service, + "matrix.send_message" + | "matrix.rooms_send" + | "matrix.reply" + | "matrix.thread_reply" + | "matrix.react" + | "matrix.typing" + | "matrix.read_receipt" + | "matrix.pin" + | "matrix.favorite" + | "matrix.low_priority" + | "matrix.mark_unread" + | "matrix.invite" + | "matrix.join" + | "matrix.invite_respond" + | "matrix.dm_open" + ) +} +pub fn room_access_allowed(room: &str, access: RoomAccess) -> bool { + ensure_room_access(room, access).is_ok() +} +pub fn ensure_room_access(room: &str, access: RoomAccess) -> Result<(), String> { + check()?; + CONTEXT.with(|ctx| { + if !ctx.lease.permits_room(room) + || (matches!(access, RoomAccess::Write) && !writing(&ctx.service)) + { + return Err(ROOM_ACCESS_DENIED.into()); + } + Ok(()) + }) +} +pub fn global_room_access_allowed(room: &str, access: RoomAccess) -> bool { + if room.is_empty() && matches!(access, RoomAccess::Write) { + return check().is_ok() && CONTEXT.with(|ctx| ctx.service == "matrix.dm_open"); + } + room_access_allowed(room, access) +} +pub fn ensure_server_output(server: &str) -> Result<(), String> { + check()?; + CONTEXT.with(|ctx| { + if ctx.client.homeserver().as_str() != server { + return Err("Matrix endpoint changed".into()); + } + Ok(()) + }) +} +pub fn commit_sensitive_target(target: &str, _content: &serde_json::Value) -> Result<(), String> { + check()?; + if target == "host" && CONTEXT.with(|ctx| ctx.service == "matrix.dm_open") { + return Ok(()); + } + ensure_room_access(target, RoomAccess::Write) +} +pub async fn audit_server_operation(server: &str, future: F) -> Result +where + F: IntoFuture>, + E: std::fmt::Display, +{ + ensure_server_output(server)?; + let future = future.into_future(); + tokio::pin!(future); + // Stop waiting on a revoked account/instance, including when the server stalls. + let result = loop { + tokio::select! { + result = &mut future => break result.map_err(|e| e.to_string()), + _ = tokio::time::sleep(std::time::Duration::from_millis(100)) => check()?, + } + }; + check()?; + result +} +pub async fn audit_room_operation(room: &str, future: F) -> Result +where + F: IntoFuture>, + E: std::fmt::Display, +{ + ensure_room_access(room, RoomAccess::Write)?; + let server = get_client() + .ok_or("Not logged in")? + .homeserver() + .to_string(); + let result = audit_server_operation(&server, future).await; + ensure_room_access(room, RoomAccess::Write)?; + result +} diff --git a/src/octoscript_apps/matrix/room.rs b/src/octoscript_apps/matrix/room.rs new file mode 100644 index 00000000..9a80c47a --- /dev/null +++ b/src/octoscript_apps/matrix/room.rs @@ -0,0 +1,608 @@ +// SPDX-License-Identifier: MIT +// Adapted from project-robius/robrix src/a2app/matrix/room.rs +// Source revision: d4d39612fdee574a0f6a33480a19868f1ec85644 +//! Services on the instance's attached room: info, messages, members, pins, threads. + +use matrix_sdk::deserialized_responses::TimelineEvent; +use matrix_sdk::ruma::events::receipt::{ReceiptThread, ReceiptType}; +use matrix_sdk::ruma::events::room::message::sanitize::remove_plain_reply_fallback; +use matrix_sdk::ruma::events::room::message::{OriginalSyncRoomMessageEvent, Relation}; +use matrix_sdk::ruma::events::{AnySyncMessageLikeEvent, AnySyncTimelineEvent, SyncMessageLikeEvent}; +use matrix_sdk::ruma::{OwnedEventId, OwnedRoomId, OwnedUserId}; +use std::collections::HashMap; + +use super::policy::{current_user_id, get_client}; +use super::clip_chars; + +/// The event as an `m.room.message`, or None for state, reactions, redactions and the like. +fn as_message(event: &TimelineEvent) -> Option { + match event.raw().deserialize() { + Ok(AnySyncTimelineEvent::MessageLike(AnySyncMessageLikeEvent::RoomMessage( + SyncMessageLikeEvent::Original(msg), + ))) => Some(msg), + _ => None, + } +} + +/// How many chars a message body is clipped to for the mini-app service +/// reads. The AI's own read tools ask for the body whole (see `full_body`), +/// because the model has to quote and reason about what a human actually +/// wrote — a truncated body makes it report that the tool cut the message. +const SERVICE_BODY_CLIP: usize = 500; + +/// The `{sender, sender_id, event_id, body, ts, msgtype}` shape every message list carries. +/// +/// `full_body` keeps the whole message text; only the mini-app services clip +/// (to `SERVICE_BODY_CLIP`), so a scripted reader does not have to guard +/// against a megabyte message. The AI read tools pass `true`. +fn message_json(msg: &OriginalSyncRoomMessageEvent, full_body: bool) -> serde_json::Value { + let mut body = remove_plain_reply_fallback(msg.content.body()).to_string(); + if !full_body { + clip_chars(&mut body, SERVICE_BODY_CLIP); + } + serde_json::json!({ + "sender": msg.sender.localpart(), + "sender_id": msg.sender, + "event_id": msg.event_id, + "body": body, + "ts": u64::from(msg.origin_server_ts.0), + "msgtype": msg.content.msgtype(), + }) +} + +/// The timestamp of the user's own newest read receipt (public or private) +/// in this room, if they have ever read it. Everything at or before that +/// point counts as read; everything after it, unread. +async fn my_read_receipt_ts(room: &matrix_sdk::Room) -> Option { + let me = current_user_id()?; + let candidates = [ + room.load_user_receipt(ReceiptType::Read, &ReceiptThread::Unthreaded, &me) + .await + .ok() + .flatten(), + room.load_user_receipt(ReceiptType::ReadPrivate, &ReceiptThread::Unthreaded, &me) + .await + .ok() + .flatten(), + ]; + candidates + .into_iter() + .flatten() + .max_by_key(|(_, r)| r.ts) + .and_then(|(_, r)| r.ts) + .map(|t| u64::from(t.0)) +} + +/// Whether `msg` is still unread by the user: someone else sent it, and it +/// is newer than the user's own read receipt. The user's own messages are +/// always read (they wrote them). +fn is_unread( + msg: &OriginalSyncRoomMessageEvent, + my_read_ts: Option, + me: &OwnedUserId, +) -> bool { + msg.sender != *me + && my_read_ts.is_none_or(|read_ts| u64::from(msg.origin_server_ts.0) > read_ts) +} + +/// Adds the read-model context shared by the room-read rows to one row: +/// which room the message is in (so a caller can build a permalink to it, +/// including across rooms) and whether the user has already read it. +fn add_row_context( + mut row: serde_json::Value, + msg: &OriginalSyncRoomMessageEvent, + room_id: &OwnedRoomId, + my_read_ts: Option, + me: &OwnedUserId, +) -> serde_json::Value { + row["room_id"] = room_id.to_string().into(); + row["unread"] = is_unread(msg, my_read_ts, me).into(); + row +} + +/// Read cached relations without sending an app-selected event id. A cache +/// miss may fetch only after every source permits the homeserver origin. +async fn protected_event_with_relations( + room: &matrix_sdk::Room, + event_id: &matrix_sdk::ruma::EventId, + filter: Option>, +) -> Result<(TimelineEvent, Vec), String> { + if let Ok((cache, _guard)) = room.event_cache().await + && let Ok(Some(cached)) = cache + .find_event_with_relations(event_id, filter.clone()) + .await + { + // The SDK's load-or-fetch helper fetches even a cached event when its + // relations are empty. Keep that network fallback explicit here. + return Ok(cached); + } + super::policy::ensure_server_output(room.client().homeserver().as_str())?; + super::policy::audit_server_operation( + room.client().homeserver().as_str(), + room.load_or_fetch_event_with_relations(event_id, filter, None), + ) + .await + .map_err(|e| format!("couldn't load the event: {e}")) +} + +pub(super) async fn thread_replies( + room_id: OwnedRoomId, + event_id: OwnedEventId, + limit: u32, +) -> Result { + use matrix_sdk::ruma::events::relation::RelationType; + super::policy::ensure_room_access(room_id.as_str(), super::policy::RoomAccess::Read)?; + let client = get_client().ok_or("not logged in")?; + let room = client.get_room(&room_id).ok_or("room not found")?; + let (root, related) = + protected_event_with_relations(&room, &event_id, Some(vec![RelationType::Thread])).await?; + // The two sources order relations differently, so sort by time ourselves. + let mut replies: Vec = + related.iter().filter_map(as_message).collect(); + replies.sort_by_key(|m| m.origin_server_ts); + let newest = replies.len().saturating_sub(limit as usize); + let replies: Vec = replies[newest..] + .iter() + .map(|m| message_json(m, false)) + .collect(); + Ok(serde_json::json!({ + "root": as_message(&root).map(|m| message_json(&m, false)), + "replies": replies, + }) + .to_string()) +} + +pub(crate) async fn older_messages( + room_id: OwnedRoomId, + before: Option, + limit: u32, + full_body: bool, +) -> Result { + use matrix_sdk::room::MessagesOptions; + super::policy::ensure_room_access(room_id.as_str(), super::policy::RoomAccess::Read)?; + let client = get_client().ok_or("not logged in")?; + let room = client.get_room(&room_id).ok_or("room not found")?; + let limit = limit as usize; + let me = current_user_id().ok_or("not logged in")?; + let my_read_ts = my_read_receipt_ts(&room).await; + // No anchor means "older than the cached window", i.e. where read_messages stops. + let caller_selected_anchor = before.is_some(); + let mut anchor = before; + if anchor.is_none() + && let Ok((cache, _guard)) = client.event_cache().room(&room_id).await + && let Ok(events) = cache.events().await + { + anchor = events + .first() + .and_then(|e| e.event_id()) + .map(ToOwned::to_owned); + } + let mut out: Vec = Vec::new(); + let mut from: Option = None; + if let Some(anchor) = &anchor { + // /context splits its budget across both sides of the anchor. + super::policy::ensure_room_access(room_id.as_str(), super::policy::RoomAccess::Read)?; + if caller_selected_anchor { + super::policy::ensure_server_output(client.homeserver().as_str())?; + } + let context = super::policy::audit_server_operation( + client.homeserver().as_str(), + room.event_with_context(anchor, true, (limit as u32 * 2).into(), None), + ) + .await + .map_err(|e| format!("couldn't load older messages: {e}"))?; + out.extend( + context + .events_before + .iter() + .filter_map(as_message) + .map(|m| { + add_row_context(message_json(&m, full_body), &m, &room_id, my_read_ts, &me) + }), + ); + from = context.prev_batch_token; + } + // Top up from /messages when the page was mostly state events, or had no anchor. + for _ in 0..4 { + super::policy::ensure_room_access(room_id.as_str(), super::policy::RoomAccess::Read)?; + if out.len() >= limit || (anchor.is_some() && from.is_none()) { + break; + } + let mut options = MessagesOptions::backward(); + options.limit = 50u32.into(); + options.from = from; + let messages = super::policy::audit_server_operation( + client.homeserver().as_str(), + room.messages(options), + ) + .await + .map_err(|e| format!("couldn't load older messages: {e}"))?; + out.extend( + messages.chunk.iter().filter_map(as_message).map(|m| { + add_row_context(message_json(&m, full_body), &m, &room_id, my_read_ts, &me) + }), + ); + from = messages.end; + if from.is_none() { + break; + } + } + let has_more = from.is_some() || out.len() > limit; + out.truncate(limit); + // Both endpoints answer newest-first; apps read oldest-first. + out.reverse(); + Ok(serde_json::json!({ "messages": out, "has_more": has_more }).to_string()) +} + +pub(super) async fn event(room_id: OwnedRoomId, event_id: OwnedEventId) -> Result { + use matrix_sdk::ruma::events::relation::RelationType; + super::policy::ensure_room_access(room_id.as_str(), super::policy::RoomAccess::Read)?; + let client = get_client().ok_or("not logged in")?; + let room = client.get_room(&room_id).ok_or("room not found")?; + let me = current_user_id().ok_or("not logged in")?; + let filter = Some(vec![RelationType::Annotation, RelationType::Replacement]); + let (event, related) = protected_event_with_relations(&room, &event_id, filter).await?; + let msg = as_message(&event).ok_or("that event isn't a message")?; + // Start from the server's bundled edit; a later synced edit wins on time. + let mut latest_edit = msg.unsigned.relations.replace.as_deref().cloned(); + let mut reactions: Vec<(String, u64, bool)> = Vec::new(); + for rel in &related { + match rel.raw().deserialize() { + Ok(AnySyncTimelineEvent::MessageLike(AnySyncMessageLikeEvent::Reaction( + SyncMessageLikeEvent::Original(reaction), + ))) => { + let key = reaction.content.relates_to.key; + let mine = reaction.sender == me; + match reactions.iter_mut().find(|(k, ..)| *k == key) { + Some((_, count, by_me)) => { + *count += 1; + *by_me |= mine; + } + None => reactions.push((key, 1, mine)), + } + } + Ok(AnySyncTimelineEvent::MessageLike(AnySyncMessageLikeEvent::RoomMessage( + SyncMessageLikeEvent::Original(edit), + ))) if edit.sender == msg.sender + && matches!(edit.content.relates_to, Some(Relation::Replacement(_))) + && latest_edit + .as_ref() + .is_none_or(|e| e.origin_server_ts < edit.origin_server_ts) => + { + latest_edit = Some(edit); + } + _ => {} + } + } + let mut out = message_json(&msg, false); + if let Some(Relation::Replacement(edit)) = latest_edit + .as_ref() + .and_then(|e| e.content.relates_to.as_ref()) + { + let mut body = remove_plain_reply_fallback(edit.new_content.msgtype.body()).to_string(); + clip_chars(&mut body, SERVICE_BODY_CLIP); + out["body"] = body.into(); + } + out["edited"] = latest_edit.is_some().into(); + out["reactions"] = reactions + .into_iter() + .map(|(key, count, mine)| serde_json::json!({ "key": key, "count": count, "mine": mine })) + .collect(); + out["thread_root"] = match &msg.content.relates_to { + Some(Relation::Thread(thread)) => serde_json::json!(thread.event_id), + _ => serde_json::Value::Null, + }; + Ok(out.to_string()) +} + +pub(super) async fn read_receipts( + room_id: OwnedRoomId, + user_id: Option, +) -> Result { + use matrix_sdk::RoomMemberships; + use matrix_sdk::ruma::events::receipt::{ReceiptThread, ReceiptType}; + // The user's "show read receipts" switch hides everyone's position, apps included. + if !crate::settings::app_preferences::show_read_receipts() { + return Ok(serde_json::json!({ "receipts": [] }).to_string()); + } + super::policy::ensure_room_access(room_id.as_str(), super::policy::RoomAccess::Read)?; + let client = get_client().ok_or("not logged in")?; + let room = client.get_room(&room_id).ok_or("room not found")?; + let members = match user_id { + Some(user_id) => { + let member = room + .get_member_no_sync(&user_id) + .await + .map_err(|e| format!("couldn't look up that member: {e}"))? + .ok_or("that user isn't in this room")?; + vec![member] + } + None => room + .members_no_sync(RoomMemberships::JOIN) + .await + .map_err(|e| format!("couldn't load members: {e}"))?, + }; + let me = current_user_id(); + let mut out: Vec<(u64, serde_json::Value)> = Vec::new(); + for member in members.iter().take(200) { + let user_id = member.user_id(); + let mut candidates = vec![ + room.load_user_receipt(ReceiptType::Read, &ReceiptThread::Unthreaded, user_id) + .await + .ok() + .flatten(), + ]; + // Our own position may only exist as a private receipt. + if me.as_deref() == Some(user_id) { + candidates.push( + room.load_user_receipt( + ReceiptType::ReadPrivate, + &ReceiptThread::Unthreaded, + user_id, + ) + .await + .ok() + .flatten(), + ); + } + let Some((event_id, receipt)) = candidates.into_iter().flatten().max_by_key(|(_, r)| r.ts) + else { + continue; + }; + let ts = receipt.ts.map(|t| u64::from(t.0)); + out.push(( + ts.unwrap_or(0), + serde_json::json!({ + "user_id": user_id, + "name": member.name(), + "event_id": event_id, + "ts": ts, + }), + )); + } + out.sort_by_key(|(ts, _)| std::cmp::Reverse(*ts)); + let receipts: Vec = out.into_iter().map(|(_, v)| v).collect(); + Ok(serde_json::json!({ "receipts": receipts }).to_string()) +} + +pub(super) async fn unread(room_id: OwnedRoomId) -> Result { + super::policy::ensure_room_access(room_id.as_str(), super::policy::RoomAccess::Read)?; + let client = get_client().ok_or("not logged in")?; + let room = client.get_room(&room_id).ok_or("room not found")?; + Ok(serde_json::json!({ + "unread": room.num_unread_messages(), + "mentions": room.num_unread_mentions(), + "marked_unread": room.is_marked_unread(), + }) + .to_string()) +} + +pub(super) async fn power_levels(room_id: OwnedRoomId) -> Result { + use matrix_sdk::ruma::events::room::power_levels::UserPowerLevel; + use matrix_sdk::ruma::events::{MessageLikeEventType, StateEventType}; + super::policy::ensure_room_access(room_id.as_str(), super::policy::RoomAccess::Read)?; + let client = get_client().ok_or("not logged in")?; + let room = client.get_room(&room_id).ok_or("room not found")?; + let me = current_user_id().ok_or("not logged in")?; + let levels = room + .power_levels() + .await + .map_err(|e| format!("couldn't load power levels: {e}"))?; + // A room creator's power is "infinite" from room v12 on. + let mine: i64 = match levels.for_user(&me) { + UserPowerLevel::Int(int) => int.into(), + _ => i64::MAX, + }; + Ok(serde_json::json!({ + "mine": mine, + "can": { + "invite": levels.user_can_invite(&me), + "kick": levels.user_can_kick(&me), + "ban": levels.user_can_ban(&me), + "redact_others": levels.user_can_redact_event_of_other(&me), + "pin": levels.user_can_send_state(&me, StateEventType::RoomPinnedEvents), + "send_message": levels.user_can_send_message(&me, MessageLikeEventType::RoomMessage), + "notify_room": levels.user_can_trigger_room_notification(&me), + "change_settings": levels.user_can_send_state(&me, StateEventType::RoomName) + && levels.user_can_send_state(&me, StateEventType::RoomTopic), + }, + }) + .to_string()) +} + +pub(super) async fn permalink( + room_id: OwnedRoomId, + event_id: Option, + use_matrix_scheme: bool, +) -> Result { + super::policy::ensure_room_access(room_id.as_str(), super::policy::RoomAccess::Read)?; + let client = get_client().ok_or("not logged in")?; + let room = client.get_room(&room_id).ok_or("room not found")?; + let url = match (use_matrix_scheme, event_id) { + (true, Some(event_id)) => room + .matrix_event_permalink(event_id) + .await + .map(|u| u.to_string()), + (true, None) => room.matrix_permalink(false).await.map(|u| u.to_string()), + (false, Some(event_id)) => room + .matrix_to_event_permalink(event_id) + .await + .map(|u| u.to_string()), + (false, None) => room.matrix_to_permalink().await.map(|u| u.to_string()), + } + .map_err(|e| format!("couldn't build the link: {e}"))?; + Ok(serde_json::json!({ "url": url }).to_string()) +} + +pub(super) async fn successor(room_id: OwnedRoomId) -> Result { + super::policy::ensure_room_access(room_id.as_str(), super::policy::RoomAccess::Read)?; + let client = get_client().ok_or("not logged in")?; + let room = client.get_room(&room_id).ok_or("room not found")?; + let Some(successor) = room.successor_room() else { + return Ok(serde_json::json!({ + "upgraded": false, "room_id": null, "name": null, "reason": null, + }) + .to_string()); + }; + super::policy::ensure_room_access(successor.room_id.as_str(), super::policy::RoomAccess::Read)?; + let name = match client.get_room(&successor.room_id) { + Some(next) => match next.cached_display_name() { + Some(name) => Some(name.to_string()), + None => next.display_name().await.ok().map(|n| n.to_string()), + }, + None => None, + }; + Ok(serde_json::json!({ + "upgraded": true, + "room_id": successor.room_id, + "name": name, + "reason": successor.reason, + }) + .to_string()) +} +/// `matrix.room_info`, and `matrix.rooms_info` for any joined room. +pub(crate) async fn info(room_id: matrix_sdk::ruma::OwnedRoomId) -> Result { + use matrix_sdk::RoomState; + use super::policy::get_client; + super::policy::ensure_room_access(room_id.as_str(), super::policy::RoomAccess::Read)?; + let client = get_client().ok_or("not logged in")?; + let room = client.get_room(&room_id).ok_or("room not found")?; + if room.state() != RoomState::Joined { + return Err("room not joined".into()); + } + let room_name = room + .display_name() + .await + .map(|n| n.to_string()) + .unwrap_or_else(|_| room_id.to_string()); + let join_rule = room + .join_rule() + .map(|r| r.as_str().to_string()) + .unwrap_or_else(|| String::from("unknown")); + let history = room.history_visibility_or_default().as_str().to_string(); + let body = serde_json::json!({ + "room_id": room_id.to_string(), + "room_name": room_name, + "topic": room.topic().unwrap_or_default(), + "member_count": room.active_members_count(), + "encrypted": room.encryption_state().is_encrypted(), + "join_rule": join_rule, + "history_visibility": history, + "alias": room.canonical_alias().map(|a| a.to_string()), + }); + Ok(body.to_string()) +} + +/// One row of `read_messages`. The walk is newest-first, so an edit shows up +/// before the message it replaces: keep its body and hand it to the original. +fn push_message( + out: &mut Vec, + edits: &mut HashMap, + msg: OriginalSyncRoomMessageEvent, + room_id: &OwnedRoomId, + my_read_ts: Option, + me: &OwnedUserId, + full_body: bool, +) { + if let Some(Relation::Replacement(edit)) = &msg.content.relates_to { + edits.entry(edit.event_id.clone()).or_insert_with(|| { + remove_plain_reply_fallback(edit.new_content.msgtype.body()).to_string() + }); + return; + } + let mut row = message_json(&msg, full_body); + if let Some(mut body) = edits.remove(&msg.event_id) { + if !full_body { + clip_chars(&mut body, SERVICE_BODY_CLIP); + } + row["body"] = body.into(); + } + out.push(add_row_context(row, &msg, room_id, my_read_ts, me)); +} + +/// `matrix.read_messages`, and `matrix.rooms_messages` for any joined room. +pub(crate) async fn read_messages( + room_id: matrix_sdk::ruma::OwnedRoomId, + limit: u32, + full_body: bool, +) -> Result { + use matrix_sdk::RoomState; + use matrix_sdk::room::MessagesOptions; + use super::policy::get_client; + super::policy::ensure_room_access(room_id.as_str(), super::policy::RoomAccess::Read)?; + let client = get_client().ok_or("not logged in")?; + let room = client.get_room(&room_id).ok_or("room not found")?; + if room.state() != RoomState::Joined { + return Err("room not joined".into()); + } + // The user's own read receipt marks what they have already seen, so each + // row can say whether it is unread — and the agent can focus on the + // messages the user hasn't read yet when asked to summarize. + let me = current_user_id().ok_or("not logged in")?; + let my_read_ts = my_read_receipt_ts(&room).await; + let mut out: Vec = Vec::new(); + let mut edits = HashMap::new(); + // The event cache already holds the recent timeline in + // memory; only hit the network when it can't fill the request. + if let Ok((cache, _guard)) = client.event_cache().room(&room_id).await { + if let Ok(events) = cache.events().await { + for event in events.iter().rev() { + let Ok(AnySyncTimelineEvent::MessageLike(AnySyncMessageLikeEvent::RoomMessage( + SyncMessageLikeEvent::Original(msg), + ))) = event.raw().deserialize() + else { + continue; + }; + push_message( + &mut out, &mut edits, msg, &room_id, my_read_ts, &me, full_body, + ); + if out.len() >= limit as usize { + break; + } + } + } + } + if out.len() < limit as usize { + // A room's recent tail can be all state events (profile + // changes etc), so keep paginating until we fill `limit`. + out.clear(); + edits.clear(); + let mut from: Option = None; + for _ in 0..4 { + super::policy::ensure_room_access(room_id.as_str(), super::policy::RoomAccess::Read)?; + let mut options = MessagesOptions::backward(); + options.limit = 50u32.into(); + options.from = from; + let messages = super::policy::audit_server_operation( + client.homeserver().as_str(), + room.messages(options), + ) + .await + .map_err(|e| format!("couldn't read messages: {e}"))?; + for event in messages.chunk { + let Ok(AnySyncTimelineEvent::MessageLike(AnySyncMessageLikeEvent::RoomMessage( + SyncMessageLikeEvent::Original(msg), + ))) = event.raw().deserialize() + else { + continue; + }; + push_message( + &mut out, &mut edits, msg, &room_id, my_read_ts, &me, full_body, + ); + if out.len() >= limit as usize { + break; + } + } + from = messages.end; + if out.len() >= limit as usize || from.is_none() { + break; + } + } + } + // Backward pagination is newest-first; apps read oldest-first. + out.reverse(); + Ok( + serde_json::json!({ "messages": out, "unread_count": room.num_unread_messages() }) + .to_string(), + ) +} diff --git a/src/octoscript_apps/matrix/rooms.rs b/src/octoscript_apps/matrix/rooms.rs new file mode 100644 index 00000000..dc30ebcd --- /dev/null +++ b/src/octoscript_apps/matrix/rooms.rs @@ -0,0 +1,166 @@ +// SPDX-License-Identifier: MIT +// Adapted from project-robius/robrix src/a2app/matrix/rooms.rs +// Source revision: d4d39612fdee574a0f6a33480a19868f1ec85644 +//! Services across many rooms: the room list and search. + +use matrix_sdk::{Room, RoomState}; +use matrix_sdk::ruma::{OwnedRoomId, OwnedRoomOrAliasId, OwnedServerName, RoomAliasId}; +use matrix_sdk::ruma::room::RoomType; + +use super::policy::get_client; +use super::policy::RoomAccess; +use super::policy::{ensure_room_access, room_access_allowed}; + +/// The cached name when there is one; computing it can read the member store. +pub(super) async fn room_name(room: &Room) -> String { + match room.cached_display_name() { + Some(name) => name.to_string(), + None => room + .display_name() + .await + .map(|n| n.to_string()) + .unwrap_or_else(|_| room.room_id().to_string()), + } +} + +pub(super) async fn search(query: String, limit: u32) -> Result { + let client = get_client().ok_or("not logged in")?; + let needle = query.to_lowercase(); + let mut out: Vec = Vec::new(); + for room in client + .joined_rooms() + .into_iter() + .chain(client.invited_rooms()) + { + if !room_access_allowed(room.room_id().as_str(), RoomAccess::Read) { + continue; + } + let name = room_name(&room).await; + let alias_hit = room + .canonical_alias() + .is_some_and(|a| a.as_str().to_lowercase().contains(&needle)); + if !name.to_lowercase().contains(&needle) && !alias_hit { + continue; + } + out.push(serde_json::json!({ + "room_id": room.room_id(), + "name": name, + "is_direct": room.is_direct().await.unwrap_or(false), + "is_space": room.is_space(), + "member_count": room.joined_members_count(), + "is_encrypted": room.encryption_state().is_encrypted(), + "unread": room.num_unread_messages(), + "mentions": room.num_unread_mentions(), + "joined": room.state() == RoomState::Joined, + })); + if out.len() >= limit as usize { + break; + } + } + Ok(serde_json::json!({ "rooms": out }).to_string()) +} + +/// Every joined room the model may offer to read, as JSON rows with the +/// name and id (plus direct/space/encryption/unread flags). The read tools' +/// `list_rooms` fetches this; the shape matches `matrix.rooms_list`. +pub(crate) async fn joined_rooms_list() -> Result { + let client = get_client().ok_or("not logged in")?; + let mut out: Vec = Vec::new(); + for room in client.joined_rooms() { + if !room_access_allowed(room.room_id().as_str(), RoomAccess::Read) { + continue; + } + out.push(serde_json::json!({ + "room_id": room.room_id(), + "name": room_name(&room).await, + "is_direct": room.is_direct().await.unwrap_or(false), + "is_space": room.is_space(), + "member_count": room.joined_members_count(), + "is_encrypted": room.encryption_state().is_encrypted(), + "unread": room.num_unread_messages(), + "mentions": room.num_unread_mentions(), + })); + } + Ok(serde_json::json!({ "rooms": out }).to_string()) +} + +pub(super) async fn invites() -> Result { + let client = get_client().ok_or("not logged in")?; + let mut out: Vec = Vec::new(); + for room in client.invited_rooms() { + if !room_access_allowed(room.room_id().as_str(), RoomAccess::Read) { + continue; + } + let invite = room.invite_details().await.ok(); + let inviter_name = invite.as_ref().map(|i| match &i.inviter { + Some(member) => member.name().to_string(), + None => i.inviter_id.localpart().to_string(), + }); + out.push(serde_json::json!({ + "room_id": room.room_id(), + "name": room_name(&room).await, + "is_space": room.is_space(), + "is_direct": room.is_direct().await.unwrap_or(false), + "inviter_id": invite.as_ref().map(|i| &i.inviter_id), + "inviter_name": inviter_name, + })); + } + Ok(serde_json::json!({ "invites": out }).to_string()) +} + +pub(super) async fn preview( + room: OwnedRoomOrAliasId, + mut via: Vec, +) -> Result { + let client = get_client().ok_or("not logged in")?; + let target = resolve_room_id(&client, &room, &mut via).await?; + ensure_room_access(target.as_str(), RoomAccess::Read)?; + let room = OwnedRoomOrAliasId::from(target); + super::policy::ensure_server_output(client.homeserver().as_str())?; + let preview = super::policy::audit_server_operation( + client.homeserver().as_str(), + client.get_room_preview(&room, via), + ) + .await + .map_err(|e| format!("couldn't preview the room: {e}"))?; + ensure_room_access(preview.room_id.as_str(), RoomAccess::Read)?; + let name = preview + .name + .clone() + .or_else(|| preview.canonical_alias.as_ref().map(|a| a.to_string())) + .unwrap_or_else(|| preview.room_id.to_string()); + Ok(serde_json::json!({ + "room_id": preview.room_id, + "name": name, + "topic": preview.topic.unwrap_or_default(), + "member_count": preview.num_joined_members, + "join_rule": preview.join_rule.as_ref().map(|r| r.as_str()).unwrap_or("unknown"), + "is_space": matches!(preview.room_type, Some(RoomType::Space)), + "joined": preview.state == Some(RoomState::Joined), + }) + .to_string()) +} + +pub(super) async fn resolve_room_id( + client: &matrix_sdk::Client, + room: &OwnedRoomOrAliasId, + via: &mut Vec, +) -> Result { + if room.as_str().starts_with('!') { + return OwnedRoomId::try_from(room.as_str()).map_err(|_| "invalid room id".to_string()); + } + let alias = <&RoomAliasId>::try_from(room.as_str()).map_err(|_| "invalid room alias")?; + super::policy::ensure_server_output(client.homeserver().as_str())?; + let resolved = super::policy::audit_server_operation( + client.homeserver().as_str(), + client.resolve_room_alias(alias), + ) + .await + .map_err(|e| format!("couldn't resolve the room alias: {e}"))?; + for server in resolved.servers { + if !via.contains(&server) { + via.push(server); + } + } + Ok(resolved.room_id) +} diff --git a/src/octoscript_apps/matrix/send.rs b/src/octoscript_apps/matrix/send.rs new file mode 100644 index 00000000..75427e12 --- /dev/null +++ b/src/octoscript_apps/matrix/send.rs @@ -0,0 +1,317 @@ +// SPDX-License-Identifier: MIT +// Adapted from project-robius/robrix src/a2app/matrix/send.rs +// Source revision: d4d39612fdee574a0f6a33480a19868f1ec85644 +//! Writes into the attached room: messages, replies, reactions, typing, +//! receipts and the room's own flags. + +use matrix_sdk::ruma::{OwnedEventId, OwnedRoomId}; +use matrix_sdk::ruma::events::room::message::RoomMessageEventContent; + +use rinx_miniapp_core::matrix::RoomFlag; + +use crate::home::rooms_list::{enqueue_rooms_list_update, RoomsListUpdate}; +use super::policy::get_client; + +pub(super) async fn message(room_id: OwnedRoomId, body: String) -> Result { + super::policy::ensure_room_access(room_id.as_str(), super::policy::RoomAccess::Write)?; + let client = get_client().ok_or("not logged in")?; + let room = client.get_room(&room_id).ok_or("room not found")?; + let content = RoomMessageEventContent::text_plain(body); + super::policy::commit_sensitive_target( + room_id.as_str(), + &serde_json::to_value(&content).map_err(|_| "Cannot review message content.")?, + )?; + super::policy::audit_room_operation(room_id.as_str(), room.send(content)) + .await + .map_err(|e| format!("couldn't send the message: {e}"))?; + Ok(String::from("{}")) +} + +pub(super) async fn reply( + room_id: OwnedRoomId, + event_id: OwnedEventId, + body: String, + in_thread: bool, +) -> Result { + use matrix_sdk::room::reply::{EnforceThread, Reply}; + use matrix_sdk::ruma::events::room::message::{ + AddMentions, ReplyWithinThread, RoomMessageEventContentWithoutRelation, + }; + super::policy::ensure_room_access(room_id.as_str(), super::policy::RoomAccess::Write)?; + let client = get_client().ok_or("not logged in")?; + let room = client.get_room(&room_id).ok_or("room not found")?; + super::policy::ensure_server_output(client.homeserver().as_str())?; + // A thread post isn't a reply to the root, so it gets no mention; a plain + // reply mentions its target the way the composer does. + let reply = if in_thread { + Reply { + event_id, + enforce_thread: EnforceThread::Threaded(ReplyWithinThread::No), + add_mentions: AddMentions::No, + } + } else { + Reply { + event_id, + enforce_thread: EnforceThread::MaybeThreaded, + add_mentions: AddMentions::Yes, + } + }; + let content = super::policy::audit_server_operation( + client.homeserver().as_str(), + room.make_reply_event( + RoomMessageEventContentWithoutRelation::text_plain(body), + reply, + ), + ) + .await + .map_err(|e| format!("couldn't build the reply: {e}"))?; + super::policy::ensure_room_access(room_id.as_str(), super::policy::RoomAccess::Write)?; + super::policy::ensure_server_output(client.homeserver().as_str())?; + super::policy::commit_sensitive_target( + room_id.as_str(), + &serde_json::to_value(&content).map_err(|_| "Cannot review reply content.")?, + )?; + let sent = super::policy::audit_room_operation(room_id.as_str(), room.send(content)) + .await + .map_err(|e| format!("couldn't send the reply: {e}"))?; + Ok(serde_json::json!({ "event_id": sent.response.event_id }).to_string()) +} + +pub(super) async fn react( + room_id: OwnedRoomId, + event_id: OwnedEventId, + key: String, +) -> Result { + use matrix_sdk::room::{IncludeRelations, RelationsOptions}; + use matrix_sdk::ruma::events::reaction::ReactionEventContent; + use matrix_sdk::ruma::events::relation::{Annotation, RelationType}; + use matrix_sdk::ruma::events::{ + AnySyncMessageLikeEvent, AnySyncTimelineEvent, SyncMessageLikeEvent, + }; + super::policy::ensure_room_access(room_id.as_str(), super::policy::RoomAccess::Write)?; + let client = get_client().ok_or("not logged in")?; + let room = client.get_room(&room_id).ok_or("room not found")?; + super::policy::ensure_server_output(client.homeserver().as_str())?; + // Page through the event's reactions until we find our own with this key. + let mut from = None; + let mine = loop { + let opts = RelationsOptions { + from, + include_relations: IncludeRelations::RelationsOfType(RelationType::Annotation), + ..Default::default() + }; + super::policy::ensure_server_output(client.homeserver().as_str())?; + let page = super::policy::audit_server_operation( + client.homeserver().as_str(), + room.relations(event_id.clone(), opts), + ) + .await + .map_err(|e| format!("couldn't load the reactions: {e}"))?; + let found = page.chunk.iter().find_map(|event| { + let Ok(AnySyncTimelineEvent::MessageLike(AnySyncMessageLikeEvent::Reaction( + SyncMessageLikeEvent::Original(reaction), + ))) = event.raw().deserialize() + else { + return None; + }; + (&*reaction.sender == room.own_user_id() && reaction.content.relates_to.key == key) + .then_some(reaction.event_id) + }); + if found.is_some() || page.prev_batch_token.is_none() { + break found; + } + from = page.prev_batch_token; + }; + super::policy::ensure_room_access(room_id.as_str(), super::policy::RoomAccess::Write)?; + super::policy::ensure_server_output(client.homeserver().as_str())?; + let added = match mine { + Some(reaction_id) => { + super::policy::commit_sensitive_target( + room_id.as_str(), + &serde_json::json!({ "remove_reaction": reaction_id, "event_id": event_id, "key": key }), + )?; + super::policy::audit_server_operation( + client.homeserver().as_str(), + room.redact(&reaction_id, None, None), + ) + .await + .map_err(|e| format!("couldn't remove the reaction: {e}"))?; + false + } + None => { + let content = ReactionEventContent::new(Annotation::new(event_id, key)); + super::policy::commit_sensitive_target( + room_id.as_str(), + &serde_json::to_value(&content).map_err(|_| "Cannot review reaction content.")?, + )?; + super::policy::audit_room_operation(room_id.as_str(), room.send(content)) + .await + .map_err(|e| format!("couldn't send the reaction: {e}"))?; + true + } + }; + Ok(serde_json::json!({ "added": added }).to_string()) +} + +pub(super) async fn typing(room_id: OwnedRoomId, typing: bool) -> Result { + super::policy::ensure_room_access(room_id.as_str(), super::policy::RoomAccess::Write)?; + let client = get_client().ok_or("not logged in")?; + let room = client.get_room(&room_id).ok_or("room not found")?; + super::policy::ensure_server_output(client.homeserver().as_str())?; + super::policy::commit_sensitive_target( + room_id.as_str(), + &serde_json::json!({ "typing": typing }), + )?; + super::policy::audit_server_operation(client.homeserver().as_str(), room.typing_notice(typing)) + .await + .map_err(|e| format!("couldn't send the typing notice: {e}"))?; + Ok(String::from("{}")) +} + +pub(super) async fn read_receipt( + room_id: OwnedRoomId, + event_id: Option, +) -> Result { + use matrix_sdk::room::Receipts; + use matrix_sdk::ruma::api::client::receipt::create_receipt::v3::ReceiptType; + use matrix_sdk::ruma::events::receipt::ReceiptThread; + use matrix_sdk_base::latest_event::LatestEventValue; + use crate::settings::app_preferences::preferred_receipt_type; + super::policy::ensure_room_access(room_id.as_str(), super::policy::RoomAccess::Write)?; + let client = get_client().ok_or("not logged in")?; + let room = client.get_room(&room_id).ok_or("room not found")?; + super::policy::ensure_server_output(client.homeserver().as_str())?; + let receipt_type = preferred_receipt_type(); + if let Some(event_id) = event_id { + super::policy::commit_sensitive_target( + room_id.as_str(), + &serde_json::json!({ "event_id": event_id, "type": receipt_type, "thread": "unthreaded" }), + )?; + super::policy::audit_server_operation( + client.homeserver().as_str(), + room.send_single_receipt(receipt_type, ReceiptThread::Unthreaded, event_id), + ) + .await + .map_err(|e| format!("couldn't send the read receipt: {e}"))?; + return Ok(String::from("{}")); + } + // Fully read means up to the newest event we know of: the SDK's + // latest-event slot first, else the tail of the event cache. + let mut latest = match room.latest_event() { + LatestEventValue::Remote(event) => event.event_id().map(ToOwned::to_owned), + _ => None, + }; + if latest.is_none() + && let Ok((cache, _guard)) = client.event_cache().room(&room_id).await + && let Ok(events) = cache.events().await + { + latest = events + .iter() + .rev() + .find_map(|e| e.event_id().map(ToOwned::to_owned)); + } + let latest = latest.ok_or("no messages to mark as read")?; + let payload = serde_json::json!({ "fully_read": latest, "receipt_event_id": latest, "receipt_type": receipt_type }); + let receipts = Receipts::new().fully_read_marker(latest.clone()); + let receipts = if matches!(receipt_type, ReceiptType::ReadPrivate) { + receipts.private_read_receipt(latest) + } else { + receipts.public_read_receipt(latest) + }; + super::policy::ensure_room_access(room_id.as_str(), super::policy::RoomAccess::Write)?; + super::policy::ensure_server_output(client.homeserver().as_str())?; + super::policy::commit_sensitive_target(room_id.as_str(), &payload)?; + super::policy::audit_server_operation( + client.homeserver().as_str(), + room.send_multiple_receipts(receipts), + ) + .await + .map_err(|e| format!("couldn't mark the room as read: {e}"))?; + Ok(String::from("{}")) +} + +pub(super) async fn pin( + room_id: OwnedRoomId, + event_id: OwnedEventId, + pinned: bool, +) -> Result { + super::policy::ensure_room_access(room_id.as_str(), super::policy::RoomAccess::Write)?; + let client = get_client().ok_or("not logged in")?; + let room = client.get_room(&room_id).ok_or("room not found")?; + super::policy::ensure_server_output(client.homeserver().as_str())?; + super::policy::commit_sensitive_target( + room_id.as_str(), + &serde_json::json!({ "event_id": event_id, "pinned": pinned }), + )?; + let result = if pinned { + super::policy::audit_server_operation( + client.homeserver().as_str(), + room.pin_event(&event_id), + ) + .await + } else { + super::policy::audit_server_operation( + client.homeserver().as_str(), + room.unpin_event(&event_id), + ) + .await + }; + result.map_err(|e| { + format!( + "couldn't {} the message: {e}", + if pinned { "pin" } else { "unpin" } + ) + })?; + Ok(String::from("{}")) +} + +pub(super) async fn room_flag( + room_id: OwnedRoomId, + flag: RoomFlag, + on: bool, +) -> Result { + super::policy::ensure_room_access(room_id.as_str(), super::policy::RoomAccess::Write)?; + let client = get_client().ok_or("not logged in")?; + let room = client.get_room(&room_id).ok_or("room not found")?; + super::policy::ensure_server_output(client.homeserver().as_str())?; + let flag_name = match flag { + RoomFlag::Favorite => "favorite", + RoomFlag::LowPriority => "low_priority", + RoomFlag::Unread => "unread", + }; + super::policy::commit_sensitive_target( + room_id.as_str(), + &serde_json::json!({ "flag": flag_name, "on": on }), + )?; + let result = match flag { + RoomFlag::Favorite => { + super::policy::audit_server_operation( + client.homeserver().as_str(), + room.set_is_favourite(on, None), + ) + .await + } + RoomFlag::LowPriority => { + super::policy::audit_server_operation( + client.homeserver().as_str(), + room.set_is_low_priority(on, None), + ) + .await + } + RoomFlag::Unread => { + super::policy::audit_server_operation( + client.homeserver().as_str(), + room.set_unread_flag(on), + ) + .await + } + }; + result.map_err(|e| format!("couldn't update the room flag: {e}"))?; + if matches!(flag, RoomFlag::Unread) { + enqueue_rooms_list_update(RoomsListUpdate::UpdateMarkedUnread { + room_id, + is_marked_unread: on, + }); + } + Ok(String::from("{}")) +} diff --git a/src/octoscript_apps/matrix/spaces.rs b/src/octoscript_apps/matrix/spaces.rs new file mode 100644 index 00000000..f7740cf8 --- /dev/null +++ b/src/octoscript_apps/matrix/spaces.rs @@ -0,0 +1,132 @@ +// SPDX-License-Identifier: MIT +// Adapted from project-robius/robrix src/a2app/matrix/spaces.rs +// Source revision: d4d39612fdee574a0f6a33480a19868f1ec85644 +//! Services on spaces: the joined spaces, one space's details, and its child rooms. + +use matrix_sdk::RoomState; +use matrix_sdk::deserialized_responses::SyncOrStrippedState; +use matrix_sdk::ruma::OwnedRoomId; +use matrix_sdk::ruma::events::SyncStateEvent; +use matrix_sdk::ruma::events::room::history_visibility::HistoryVisibility; +use matrix_sdk::ruma::events::space::child::SpaceChildEventContent; +use matrix_sdk::ruma::room::RoomType; +use matrix_sdk_ui::spaces::SpaceRoomList; +use matrix_sdk_ui::spaces::room_list::SpaceRoomListPaginationState; + +use super::rooms::room_name; +use super::policy::get_client; +use super::policy::RoomAccess; +use super::policy::{ensure_room_access, room_access_allowed}; + +pub(crate) async fn list() -> Result { + let client = get_client().ok_or("not logged in")?; + let mut out: Vec = Vec::new(); + for space in client.joined_rooms().into_iter().filter(|r| r.is_space()) { + if !room_access_allowed(space.room_id().as_str(), RoomAccess::Read) { + continue; + } + out.push(serde_json::json!({ + "space_id": space.room_id(), + "name": room_name(&space).await, + "topic": space.topic().unwrap_or_default(), + "member_count": space.joined_members_count(), + })); + } + Ok(serde_json::json!({ "spaces": out }).to_string()) +} + +pub(crate) async fn info(space_id: OwnedRoomId) -> Result { + ensure_room_access(space_id.as_str(), RoomAccess::Read)?; + let client = get_client().ok_or("not logged in")?; + let space = client.get_room(&space_id).ok_or("space not found")?; + if !space.is_space() || space.state() != RoomState::Joined { + return Err("not a joined space".into()); + } + // Counted the way the SDK's space graph does: every child state event + // that still deserializes, redactions excluded. + let children_count = space + .get_state_events_static::() + .await + .map(|children| { + children + .iter() + .filter(|c| match c.deserialize() { + Ok(SyncOrStrippedState::Sync(SyncStateEvent::Original(event))) => { + !event.content.via.is_empty() + && room_access_allowed(event.state_key.as_str(), RoomAccess::Read) + } + Ok(SyncOrStrippedState::Stripped(event)) => { + event + .content + .via + .as_ref() + .is_some_and(|via| !via.is_empty()) + && room_access_allowed(event.state_key.as_str(), RoomAccess::Read) + } + _ => false, + }) + .count() + }) + .unwrap_or(0); + let join_rule = space + .join_rule() + .map(|r| r.as_str().to_string()) + .unwrap_or_else(|| String::from("unknown")); + Ok(serde_json::json!({ + "space_id": space_id, + "name": room_name(&space).await, + "topic": space.topic().unwrap_or_default(), + "member_count": space.joined_members_count(), + "join_rule": join_rule, + "world_readable": space.history_visibility_or_default() == HistoryVisibility::WorldReadable, + "children_count": children_count, + }) + .to_string()) +} + +pub(crate) async fn rooms(space_id: OwnedRoomId) -> Result { + let check_space = || { + super::policy::global_room_access_allowed(space_id.as_str(), RoomAccess::Read) + .then_some(()) + .ok_or_else(|| super::policy::ROOM_ACCESS_DENIED.to_string()) + }; + check_space()?; + let client = get_client().ok_or("not logged in")?; + let homeserver = client.homeserver(); + let list = SpaceRoomList::new(client, space_id.clone()).await; + // Each page is one /hierarchy request; stop at the end or at the row cap. + loop { + check_space()?; + super::policy::ensure_server_output(homeserver.as_str())?; + super::policy::audit_server_operation(homeserver.as_str(), list.paginate()) + .await + .map_err(|e| format!("couldn't load the space's rooms: {e}"))?; + let done = matches!( + list.pagination_state(), + SpaceRoomListPaginationState::Idle { end_reached: true } + ); + if done || list.rooms().await.len() >= 200 { + break; + } + } + let out: Vec = list + .rooms() + .await + .into_iter() + .filter(|room| room_access_allowed(room.room_id.as_str(), RoomAccess::Read)) + .take(200) + .map(|r| { + serde_json::json!({ + "room_id": r.room_id, + "name": r.display_name, + "topic": r.topic.unwrap_or_default(), + "is_space": matches!(r.room_type, Some(RoomType::Space)), + "joined": r.state == Some(RoomState::Joined), + "member_count": r.num_joined_members, + "join_rule": r.join_rule.as_ref().map(|j| j.as_str()).unwrap_or("unknown"), + }) + }) + .collect(); + check_space()?; + Ok(serde_json::json!({ "rooms": out }).to_string()) +} diff --git a/src/octoscript_apps/mod.rs b/src/octoscript_apps/mod.rs new file mode 100644 index 00000000..5c74d41c --- /dev/null +++ b/src/octoscript_apps/mod.rs @@ -0,0 +1,43 @@ +//! Octoscript mini-app hosting with account-bound Matrix and Octos service access. +mod matrix; +pub use rinx_miniapp_core::{InstanceId, Lease, OctosProvider, ServiceEvent}; +use std::sync::LazyLock; +static AUTHORITY: LazyLock = LazyLock::new(Default::default); + +pub fn invalidate_sessions() { + AUTHORITY.invalidate(); +} + +pub async fn matrix_request( + lease: Lease, + service: String, + args: serde_json::Value, +) -> Result { + let client = crate::sliding_sync::get_client().ok_or("Not logged in")?; + matrix::execute(client, lease, service, args).await +} + +mod octos; +mod package; +pub mod ui; +pub use octos::KernelProvider; +pub use ui::{MiniAppsAction, MiniAppsPanelWidgetRefExt}; + +pub fn script_mod(vm: &mut makepad_widgets::ScriptVm) { + static ONCE: std::sync::Once = std::sync::Once::new(); + ONCE.call_once(|| { + makepad_widgets::widget_async::register_splash_isolate_mod(|vm| { + octoscript_widgets::design::script_mod(vm); + }); + makepad_widgets::widget_async::register_splash_isolate_mod(|vm| { + octoscript_widgets::kit::script_mod(vm); + }); + makepad_widgets::widget_async::register_splash_isolate_mod(|vm| { + octoscript_widgets::tap::script_mod(vm); + }); + makepad_widgets::widget_async::register_splash_isolate_mod( + makepad_widgets::splash::register_agent_module, + ); + }); + ui::script_mod(vm); +} diff --git a/src/octoscript_apps/octos.rs b/src/octoscript_apps/octos.rs new file mode 100644 index 00000000..61259fd1 --- /dev/null +++ b/src/octoscript_apps/octos.rs @@ -0,0 +1,355 @@ +//! Octos adapter over the SAME connection AppCard publishes on its UI thread. +use octos_app_transport::shared::Connection; +use rinx_miniapp_core::{InstanceId, Lease, OctosProvider, ServiceEvent}; +use serde_json::{Value, json}; +use std::sync::{ + Arc, + atomic::{AtomicU64, Ordering}, + mpsc::SyncSender, +}; + +pub struct KernelProvider { + connection: Arc, + session: String, + active_turn: Arc, + turn_namespace: u64, + workspace: Option, +} +impl KernelProvider { + pub fn shared(workspace: &std::path::Path) -> Result>, String> { + let Some(connection) = Connection::current() else { + return Ok(None); + }; + let workspace = workspace.canonicalize().map_err(|e| e.to_string())?; + Ok(Some(Self::from_connection( + connection, + Some(workspace.to_string_lossy().into_owned()), + ))) + } + fn from_connection(connection: Arc, workspace: Option) -> Arc { + static NEXT: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(1); + let nonce = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .unwrap_or_default() + .as_nanos(); + let id = NEXT.fetch_add(1, std::sync::atomic::Ordering::Relaxed); + let session = format!("{}:api:rinx-mini-{nonce:x}-{id}", connection.profile); + Arc::new(Self { + connection, + session, + active_turn: Arc::new(AtomicU64::new(0)), + turn_namespace: (uuid::Uuid::new_v4().as_u128() >> 64) as u64, + workspace, + }) + } + /// Explicit standalone configuration uses the identical WS/stdio protocol. + pub fn connect(config: octos_app_transport::TransportConfig) -> Result, String> { + let (connection, receiver) = + Connection::start(config, Arc::new(makepad_widgets::SignalToUI::set_ui_signal))?; + drop(receiver); + Ok(Self::from_connection(connection, None)) + } +} +fn turn_id(namespace: u64, number: u64) -> String { + uuid::Uuid::from_u128(((namespace as u128) << 64) | number as u128).to_string() +} +fn valid(lease: &Lease) -> Result<(), String> { + let account = crate::sliding_sync::current_user_id().ok_or("Not logged in")?; + lease.check(account.as_str()) +} +impl OctosProvider for KernelProvider { + fn request( + &self, + lease: Lease, + service: &str, + args: Value, + reply: SyncSender, + ) -> Result<(), String> { + valid(&lease)?; + let workspace = self + .workspace + .clone() + .ok_or("Open the mini app to bind its Octos workspace")?; + if !self.connection.is_active() { + return Err("Octos connection changed; reopen this app".into()); + } + lease.authorize(&lease.identity().account, service, None)?; + let method = match service { + "octos.session.open" => "session/open", + "octos.session.history" => "session/hydrate", + "octos.turn.start" => "turn/start", + "octos.turn.interrupt" => "turn/interrupt", + _ => return Err("Unknown Octos mini-app service".into()), + }; + // Apps supply input text, never session/profile/workspace identity, + // approval decisions, arbitrary RPC methods or filesystem paths. + let allowed: &[&str] = if method == "turn/start" { + &["text"] + } else { + &[] + }; + if args + .as_object() + .is_none_or(|o| o.keys().any(|k| !allowed.contains(&k.as_str()))) + { + return Err("Unsupported Octos arguments".into()); + } + let session = self.session.clone(); + static NEXT_TURN: AtomicU64 = AtomicU64::new(1); + let turn_number = if method == "turn/start" { + NEXT_TURN.fetch_add(1, Ordering::Relaxed) + } else { + self.active_turn.load(Ordering::Acquire) + }; + if method == "turn/interrupt" && turn_number == 0 { + return Err("No active Octos turn".into()); + } + let turn = turn_id(self.turn_namespace, turn_number); + let params = match method { + "session/open" => json!({"session_id":session,"profile_id":self.connection.profile, + "cwd":workspace,"sandbox":{"enabled":true,"network_access":false,"read_allow_paths":[workspace]}}), + "session/hydrate" => json!({"session_id":session,"include":["messages"]}), + "turn/start" => { + let text = args["text"] + .as_str() + .filter(|s| !s.trim().is_empty() && s.len() <= 32 * 1024) + .ok_or("Provide text (at most 32 KiB)")?; + json!({"session_id":session,"turn_id":turn,"input":[{"kind":"text","text":text}]}) + } + _ => json!({"session_id":session,"turn_id":turn}), + }; + if method == "turn/start" + && self + .active_turn + .compare_exchange(0, turn_number, Ordering::AcqRel, Ordering::Acquire) + .is_err() + { + return Err("This app already has an active Octos turn".into()); + } + let active_turn = self.active_turn.clone(); + let connection = self.connection.clone(); + self.connection.handle().spawn(async move { + let mut events = connection.subscribe(); + let work = async { + valid(&lease)?; + if matches!(method,"turn/start"|"session/hydrate") { + connection.request("session/open",json!({"session_id":session,"profile_id":connection.profile, + "cwd":workspace,"sandbox":{"enabled":true,"network_access":false,"read_allow_paths":[workspace]}})).await?; + } + let result = connection.request(method, params).await?; + valid(&lease)?; + if method != "turn/start" { return Ok(result); } + let mut stream = TurnReply::default(); + loop { + let event = events.recv().await.map_err(|_| "Octos event stream closed or fell behind; reload history")?; + if event.session_id().0 != session { continue; } + let data = serde_json::to_value(&*event).map_err(|e| e.to_string())?; + valid(&lease)?; + if !stream.accept(&turn, &data)? {continue;} + if stream.completed { + // The terminal can overtake the persisted transcript lane. + // Hydrate by THIS turn, never substitute an older answer. + let history=connection.request("session/hydrate",json!({"session_id":session,"include":["messages"]})).await?; + valid(&lease)?; + if let Some(text)=history["messages"].as_array().and_then(|rows|rows.iter().rev().find(|m|m["role"]=="assistant" && m["turn_id"]==turn)).and_then(|m|m["content"].as_str()) { + stream.text=text.to_owned(); + } + return rinx_miniapp_core::bounded_reply(json!({"text":stream.text,"event":data})); + } + let data=rinx_miniapp_core::bounded_reply(json!({"text":stream.text,"event":data}))?; + reply.try_send(ServiceEvent::Data(data)).map_err(|_| "Mini-app event consumer is unavailable")?; + makepad_widgets::SignalToUI::set_ui_signal(); + } + }; + tokio::pin!(work); + let timeout = tokio::time::sleep(std::time::Duration::from_secs(180)); + tokio::pin!(timeout); + let result = loop { + tokio::select! { + r = &mut work => break r, + _ = &mut timeout => break Err("Octos turn timed out".into()), + _ = tokio::time::sleep(std::time::Duration::from_millis(100)) => { + if let Err(e) = valid(&lease) { break Err(e); } + if !connection.is_active() { break Err("Octos connection changed".into()); } + } + } + }; + if result.is_err() && method == "turn/start" { + let _ = connection.request("turn/interrupt", json!({"session_id":session,"turn_id":turn})).await; + } + if method=="turn/start" { let _=active_turn.compare_exchange(turn_number,0,Ordering::AcqRel,Ordering::Acquire); } + let result = result.map_err(|error| { + if error.contains("401") && error.to_ascii_lowercase().contains("authentication") { + "Octos provider authentication failed (HTTP 401). Update the provider credentials in AppCard.".into() + } else { + error + } + }); + let _ = reply.try_send(ServiceEvent::Complete(result)); + makepad_widgets::SignalToUI::set_ui_signal(); + }); + Ok(()) + } + fn decide( + &self, + lease: Lease, + approval: &str, + approve: bool, + reply: SyncSender, + ) -> Result<(), String> { + valid(&lease)?; + let connection = self.connection.clone(); + let params = json!({"session_id":self.session,"approval_id":approval,"decision":if approve{"approve"}else{"deny"}}); + self.connection.handle().spawn(async move { + let result = async { + valid(&lease)?; + let result = connection.request("approval/respond", params).await?; + valid(&lease)?; + Ok(result) + } + .await; + let _ = reply.try_send(ServiceEvent::Complete(result)); + makepad_widgets::SignalToUI::set_ui_signal(); + }); + Ok(()) + } + fn close(&self, _identity: &InstanceId) { + let number = self.active_turn.load(Ordering::Acquire); + if number == 0 { + return; + } + let connection = self.connection.clone(); + let session = self.session.clone(); + let turn = turn_id(self.turn_namespace, number); + self.connection.handle().spawn(async move { + let _ = connection + .request( + "turn/interrupt", + json!({"session_id":session,"turn_id":turn}), + ) + .await; + }); + } +} + +/// Consume both protocol generations while keeping turn and segment ownership. +#[derive(Default)] +struct TurnReply { + text: String, + segment: String, + sequence: std::collections::BTreeMap, + v2: bool, + completed: bool, +} +impl TurnReply { + fn accept(&mut self, turn: &str, event: &Value) -> Result { + let envelope = &event["envelope"]; + let event_turn = event + .get("turn_id") + .or_else(|| envelope.get("turn_id")) + .and_then(Value::as_str); + if event_turn.is_some_and(|id| id != turn) { + return Ok(false); + } + match event["kind"].as_str().unwrap_or("") { + "envelope_v2" => { + if event_turn != Some(turn) { + return Ok(false); + } + if let (Some(thread), Some(seq)) = + (envelope["thread_id"].as_str(), envelope["seq"].as_u64()) + { + if self.sequence.get(thread).is_some_and(|seen| seq <= *seen) { + return Ok(false); + } + self.sequence.insert(thread.to_owned(), seq); + } + let payload = &envelope["payload"]; + let data = &payload["data"]; + match payload["type"].as_str().unwrap_or("") { + "assistant_delta" | "assistant_persisted" => { + let segment = data["assistant_segment_id"].as_str().unwrap_or(""); + if !self.v2 || self.segment != segment { + self.text.clear(); + self.segment = segment.into(); + } + self.v2 = true; + let text = data["text"].as_str().unwrap_or(""); + if payload["type"] == "assistant_persisted" { + self.text = text.into(); + } else { + self.text.push_str(text); + } + } + "turn_terminal" => { + if data["outcome"] != "completed" { + return Err(data["error"]["message"] + .as_str() + .unwrap_or("Octos turn ended without completing") + .to_owned()); + } + self.completed = true; + } + _ => {} + } + } + "message_delta" if !self.v2 => self.text.push_str(event["text"].as_str().unwrap_or("")), + "turn_completed" => self.completed = true, + "turn_error" => { + return Err(event["message"] + .as_str() + .unwrap_or("Octos turn failed") + .into()); + } + _ => {} + } + Ok(true) + } +} +#[cfg(test)] +mod tests { + use super::*; + #[test] + fn v2_final_replaces_deltas_and_ignores_other_turns_and_replay() { + let mut reply = TurnReply::default(); + assert!( + !reply + .accept( + "owned", + &json!({"kind":"message_delta","turn_id":"other","text":"private"}) + ) + .unwrap() + ); + reply + .accept( + "owned", + &json!({"kind":"message_delta","turn_id":"owned","text":"draft"}), + ) + .unwrap(); + let event = json!({"kind":"envelope_v2","envelope":{"turn_id":"owned","thread_id":"thread","seq":1,"payload":{"type":"assistant_persisted","data":{"text":"final answer","assistant_segment_id":"segment"}}}}); + assert!(reply.accept("owned", &event).unwrap()); + assert!(!reply.accept("owned", &event).unwrap()); + assert_eq!(reply.text, "final answer"); + reply + .accept( + "owned", + &json!({"kind":"message_delta","turn_id":"owned","text":"duplicate"}), + ) + .unwrap(); + assert_eq!(reply.text, "final answer"); + assert!( + reply + .accept( + "owned", + &json!({"kind":"turn_error","turn_id":"owned","message":"denied"}) + ) + .is_err() + ); + } + #[test] + fn host_turn_ids_are_protocol_uuids() { + assert!(uuid::Uuid::parse_str(&turn_id(123, 1)).is_ok()); + assert_ne!(turn_id(123, 1), turn_id(123, 2)); + assert_ne!(turn_id(123, 1), turn_id(124, 1)); + } +} diff --git a/src/octoscript_apps/package.rs b/src/octoscript_apps/package.rs new file mode 100644 index 00000000..733e0607 --- /dev/null +++ b/src/octoscript_apps/package.rs @@ -0,0 +1,358 @@ +//! Canonical OctoSense bundles; local import is visibly unsigned, never a +//! claim that a package came from a verified catalog. +use octosense_app_policy::{AppManifest, AppPolicy}; +use serde::Deserialize; +use serde_json::Value; +use std::{ + collections::BTreeMap, + path::{Path, PathBuf}, +}; + +#[derive(Clone, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct Call { + pub service: String, + #[serde(default = "object")] + pub args: Value, + pub target: String, +} +fn object() -> Value { + serde_json::json!({}) +} +#[derive(Clone, Default, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct Bindings { + #[serde(default)] + pub on_open: Vec, + #[serde(default)] + pub events: BTreeMap, +} +pub struct Package { + pub root: PathBuf, + pub manifest: AppManifest, + pub policy: AppPolicy, + pub source: String, + pub script: bool, + pub data: Value, + pub bindings: Bindings, + original: PathBuf, + _snapshot: Snapshot, +} +struct Snapshot(PathBuf); +impl Drop for Snapshot { + fn drop(&mut self) { + let _ = std::fs::remove_dir_all(&self.0); + } +} +impl Package { + #[cfg(test)] + pub fn load(root: &Path) -> Result { + Self::load_in(root, &std::env::temp_dir()) + } + pub fn load_in(root: &Path, snapshots: &Path) -> Result { + std::fs::create_dir_all(snapshots).map_err(|e| e.to_string())?; + // Freeze the admitted bytes. Source edits cannot change a running app's + // kit, images or bindings after the user reviews its grants. + let original = root.to_owned(); + let path = snapshots.join(format!("rinx-miniapp-{}", uuid::Uuid::new_v4())); + std::fs::create_dir(&path).map_err(|e| e.to_string())?; + // Own cleanup only after creating the directory: a failed admission + // must never remove another import's snapshot on a name collision. + let snapshot = Snapshot(path); + copy_bundle(root, &snapshot.0, &mut 0, &mut 0, 0)?; + let root = &snapshot.0; + let manifest = AppManifest::parse( + &std::fs::read_to_string(root.join("manifest.json")).map_err(|e| e.to_string())?, + )?; + if manifest.agent.is_some() { + return Err("Bundle agent profiles are not supported here; declare explicit octos.* services instead".into()); + } + octosense_app_policy::admit_digest( + &manifest, + &octosense_app_policy::digest_dir(root)?, + &octosense_app_policy::RefuseAllSignatures, + )?; + let policy = octosense_app_policy::policy::resolve( + &manifest, + &octosense_app_policy::HostLimits { + require_signature: false, + ..Default::default() + }, + )?; + let script = root.join(octosense_app_policy::SCRIPT_ENTRY).is_file(); + let entry = if script { + octosense_app_policy::SCRIPT_ENTRY + } else { + "page.card" + }; + let source = + std::fs::read_to_string(root.join(entry)).map_err(|e| format!("{entry}: {e}"))?; + let data = read_json(root, "page.data.json")?.unwrap_or_else(object); + if !data.is_object() { + return Err("page.data.json must be an object".into()); + } + let bindings: Bindings = + serde_json::from_value(read_json(root, "bindings.json")?.unwrap_or_else(object)) + .map_err(|e| e.to_string())?; + if script && (!bindings.on_open.is_empty() || !bindings.events.is_empty()) { + return Err( + "main.splash apps call host.request directly; bindings.json is for L0 cards".into(), + ); + } + if bindings.on_open.len() > 8 || bindings.events.len() > 64 { + return Err("Too many service bindings".into()); + } + for call in bindings.on_open.iter().chain(bindings.events.values()) { + if !manifest.capabilities.contains(&call.service) { + return Err(format!("{} is not declared in capabilities", call.service)); + } + if call.target.is_empty() + || !call + .target + .bytes() + .all(|b| b.is_ascii_alphanumeric() || b == b'_') + { + return Err("Binding target must be a top-level data name".into()); + } + if !call.args.is_object() { + return Err("Binding arguments must be an object".into()); + } + } + Ok(Self { + root: root.to_owned(), + manifest, + policy, + source, + script, + data, + bindings, + original, + _snapshot: snapshot, + }) + } + pub fn unchanged(&self) -> Result<(), String> { + let current = Self::load_in( + &self.original, + self.root.parent().ok_or("Missing bundle cache")?, + )?; + if current.manifest.signing_bytes()? != self.manifest.signing_bytes()? { + return Err("Package changed; review it again".into()); + } + Ok(()) + } +} +fn read_json(root: &Path, name: &str) -> Result, String> { + match std::fs::read_to_string(root.join(name)) { + Ok(s) => serde_json::from_str(&s) + .map(Some) + .map_err(|e| format!("{name}: {e}")), + Err(e) if e.kind() == std::io::ErrorKind::NotFound => Ok(None), + Err(e) => Err(e.to_string()), + } +} +fn copy_bundle( + source: &Path, + destination: &Path, + total: &mut u64, + count: &mut usize, + depth: usize, +) -> Result<(), String> { + if depth > 32 { + return Err("Bundle exceeds 32 directory levels".into()); + } + *count += 1; + if *count > 4096 { + return Err("Bundle exceeds 4096 entries".into()); + } + let metadata = std::fs::symlink_metadata(source).map_err(|e| e.to_string())?; + if metadata.file_type().is_symlink() { + return Err("Bundle symlinks are not allowed".into()); + } + if metadata.is_dir() { + if depth != 0 { + std::fs::create_dir(destination).map_err(|e| e.to_string())?; + } + for entry in std::fs::read_dir(source).map_err(|e| e.to_string())? { + let entry = entry.map_err(|e| e.to_string())?; + copy_bundle( + &entry.path(), + &destination.join(entry.file_name()), + total, + count, + depth + 1, + )?; + } + } else if metadata.is_file() { + use std::io::Read; + // Bound the read itself, even if the source grows while importing. + let mut bytes = Vec::new(); + std::fs::File::open(source) + .map_err(|e| e.to_string())? + .take(32 * 1024 * 1024 + 1 - *total) + .read_to_end(&mut bytes) + .map_err(|e| e.to_string())?; + *total += bytes.len() as u64; + if *total > 32 * 1024 * 1024 { + return Err("Bundle exceeds 32 MiB".into()); + } + std::fs::write(destination, bytes).map_err(|e| e.to_string())?; + } else { + return Err("Bundle contains a special file".into()); + } + Ok(()) +} +pub fn arguments( + template: &Value, + data: &Value, + state: &octoscript_ui_l0::InstanceStore, + key: &str, + payload: &Value, +) -> Result { + Ok(match template { + Value::Object(o) if o.len() == 1 && o.contains_key("$data") => data + .pointer(o["$data"].as_str().ok_or("Invalid data pointer")?) + .cloned() + .ok_or("Missing binding data")?, + Value::Object(o) if o.len() == 1 && o.contains_key("$state") => state + .get(key, o["$state"].as_str().ok_or("Invalid state field")?) + .or_else(|| { + state.get( + octoscript_ui_l0::CARD_STATE_KEY, + o["$state"].as_str().unwrap(), + ) + }) + .cloned() + .ok_or("Missing binding state")?, + Value::Object(o) if o.len() == 1 && o.get("$value") == Some(&Value::Bool(true)) => { + payload.clone() + } + Value::Object(o) => Value::Object( + o.iter() + .map(|(k, v)| Ok((k.clone(), arguments(v, data, state, key, payload)?))) + .collect::>()?, + ), + Value::Array(a) => Value::Array( + a.iter() + .map(|v| arguments(v, data, state, key, payload)) + .collect::>()?, + ), + value => value.clone(), + }) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn script_bundle_uses_the_shared_entry_and_frozen_assets() { + let path = + Path::new(env!("CARGO_MANIFEST_DIR")).join("examples/miniapps/matrix-octos-script"); + let package = Package::load(&path).unwrap(); + assert!(package.script); + assert!(package.source.contains("host.request(\"matrix.profile\"")); + assert!(package.bindings.events.is_empty()); + std::fs::write( + package.root.join("main.splash"), + "Image{src: http_resource(\"{{assets}}/icon.png\")}", + ) + .unwrap(); + let rendered = octosense_app_policy::script_source(&package.root, "http://127.0.0.1:1234/") + .unwrap() + .unwrap(); + assert_eq!( + rendered, + "Image{src: http_resource(\"http://127.0.0.1:1234/icon.png\")}" + ); + assert!(Package::load(&package.root).is_err()); + } + #[test] + fn service_results_realize_as_declared_record_state() { + let source = r#"state result {shape: record} +view root Surface { TextBody(text: result.data.display_name) } +"#; + let report = octoscript_ui_l0::realize( + source, + &serde_json::json!({"result":{"data":{"display_name":"Alice"}}}), + Default::default(), + ); + let root = report.complete_root().unwrap(); + assert!(format!("{root:?}").contains("Alice")); + } + #[test] + fn sample_bundle_uses_the_shared_renderer_and_updates_state() { + let path = Path::new(env!("CARGO_MANIFEST_DIR")).join("examples/miniapps/matrix-octos"); + let package = Package::load(&path).unwrap(); + let mut state = octoscript_ui_l0::InstanceStore::default(); + let prepared = octoscript_makepad::l0::prepare_with_state( + &package.source, + &package.data, + &state, + &path.join("kit"), + ) + .unwrap(); + let ui = octoscript_makepad::to_makepad_l0_ui(&prepared.tree); + assert!(ui.contains("Matrix + Octos")); + assert!(ui.contains("on_change")); + assert!(octoscript_ui_l0::dispatch_with_data( + &package.source, + &mut state, + octoscript_ui_l0::CARD_STATE_KEY, + "typing", + Some(&Value::String("hello".into())), + &package.data + )); + let call = &package.bindings.events["ask"]; + assert_eq!( + arguments( + &call.args, + &package.data, + &state, + octoscript_ui_l0::CARD_STATE_KEY, + &Value::Null + ) + .unwrap()["text"], + "hello" + ); + } + #[test] + fn imported_bytes_are_frozen_and_admission_rejects_tampering() { + let source = Path::new(env!("CARGO_MANIFEST_DIR")).join("examples/miniapps/matrix-octos"); + let imported = Package::load(&source).unwrap(); + // An independently admitted copy owns its bytes even if its source + // folder is edited after review. + let frozen = Package::load(&imported.root).unwrap(); + std::fs::write(imported.root.join("page.card"), "changed after review").unwrap(); + assert!(frozen.source.contains("Matrix + Octos")); + assert!(frozen.unchanged().is_err()); + assert!(Package::load(&imported.root).is_err()); + } + + #[test] + fn binding_arguments_are_data_not_identity() { + let template = serde_json::json!({"body":{"$value":true},"room_id":{"$data":"/room"}}); + let data = serde_json::json!({"room":"!allowed:example.org"}); + let args = arguments( + &template, + &data, + &Default::default(), + "root", + &Value::String("hello".into()), + ) + .unwrap(); + assert_eq!( + args, + serde_json::json!({"body":"hello","room_id":"!allowed:example.org"}) + ); + assert!( + arguments( + &serde_json::json!({"$data":"/missing"}), + &data, + &Default::default(), + "root", + &Value::Null + ) + .is_err() + ); + } +} diff --git a/src/octoscript_apps/ui.rs b/src/octoscript_apps/ui.rs new file mode 100644 index 00000000..311fbd25 --- /dev/null +++ b/src/octoscript_apps/ui.rs @@ -0,0 +1,633 @@ +//! One native mini-app screen shared by standalone and embedded Rinx. +use super::{ + InstanceId, KernelProvider, Lease, OctosProvider, ServiceEvent, + package::{Call, Package}, +}; +use makepad_widgets::splash_host::{splash_host_respond, take_splash_host_requests_for}; +use makepad_widgets::*; +use octoscript_ui_l0::InstanceStore; +use octosense_app_policy::AssetServer; +use serde_json::{Value, json}; +use std::{ + collections::VecDeque, + path::PathBuf, + sync::{ + Arc, + mpsc::{self, Receiver}, + }, + time::{Duration, Instant}, +}; + +#[derive(Clone, Debug)] +pub enum MiniAppsAction { + Open, + Close, +} +script_mod! { + use mod.prelude.widgets.* + mod.widgets.MiniAppsPanel = #(MiniAppsPanel::register_widget(vm)) { + width: Fill height: Fill flow: Down padding: 18 spacing: 12 + show_bg: true + draw_bg +: {color: instance(#xf5f5f5) pixel: fn() {return self.color}} + header := View {width: Fill height: Fit flow: Right spacing: 12 + close := Button {text: "Back"} + Label {text: "Mini apps" draw_text.color: #222 draw_text.text_style.font_size: 18} + } + import_form := View {width: Fill height: Fit flow: Down spacing: 8 + path := TextInput {width: Fill empty_text: "OctoSense bundle folder"} + room := TextInput {width: Fill empty_text: "Room ID to allow (optional)"} + core := View {width: Fill height: Fit flow: Down spacing: 6 + endpoint := TextInput {width: Fill empty_text: "Octos server URL"} + profile := TextInput {width: Fill empty_text: "Octos profile"} + token := TextInput {width: Fill is_password: true empty_text: "Octos access token"} + connect := Button {text: "Connect Octos"} + } + buttons := View {width: Fill height: Fit spacing: 8 + review := Button {text: "Review bundle"} + run := Button {text: "Run"} + } + } + notice := Label {width: Fill height: Fit draw_text.color: #333 text: "Import an OctoSense bundle to review its services."} + approval := View {visible: false width: Fill height: Fit flow: Down spacing: 8 + details := Label {width: Fill draw_text.color: #222} + buttons := View {width: Fill height: Fit spacing: 8 + allow := Button {text: "Allow once"} + deny := Button {text: "Deny"} + } + } + card := Splash {width: Fill height: Fill} + } +} +type Provider = Arc; +struct Pending { + reply: Option<(usize, u64)>, + target: Option, + receiver: Receiver, + started: Instant, + turn: bool, +} +struct Approval { + id: String, + message: String, +} +#[derive(Script, ScriptHook, Widget)] +pub struct MiniAppsPanel { + #[deref] + view: View, + #[rust] + open: bool, + #[rust] + reviewed_room: String, + #[rust] + package: Option, + #[rust] + lease: Option, + #[rust] + connection_owner: Option, + #[rust] + provider: Option, + #[rust] + tag: String, + #[rust] + state: InstanceStore, + #[rust] + data: Value, + #[rust] + pending: Vec, + #[rust] + approvals: VecDeque, + #[rust] + assets: Option, +} +impl Drop for MiniAppsPanel { + fn drop(&mut self) { + if let Some(lease) = self.lease.take() { + lease.revoke(); + if let Some(provider) = self.provider.take() { + provider.close(lease.identity()); + } + } + } +} +impl MiniAppsPanel { + fn notice(&mut self, cx: &mut Cx, message: &str) { + self.view.label(cx, ids!(notice)).set_text(cx, message); + } + fn stop(&mut self, cx: &mut Cx) { + if let Some(lease) = self.lease.take() { + lease.revoke(); + if let Some(provider) = self.provider.take() { + provider.close(lease.identity()); + } + } + self.pending.clear(); + self.assets = None; + self.approvals.clear(); + self.view.view(cx, ids!(approval)).set_visible(cx, false); + self.view.splash(cx, ids!(card)).set_text(cx, ""); + self.view.view(cx, ids!(import_form)).set_visible(cx, true); + } + fn show_approval(&mut self, cx: &mut Cx) { + if let Some(approval) = self.approvals.front() { + self.view + .label(cx, ids!(approval.details)) + .set_text(cx, &approval.message); + } + self.view + .view(cx, ids!(approval)) + .set_visible(cx, !self.approvals.is_empty()); + } + fn connect(&mut self, cx: &mut Cx) -> Result<(), String> { + #[cfg(feature = "octosense-module")] + if crate::module::is_hosted() { + return Err("This app uses OctoSense's core connection".into()); + } + let endpoint = self + .view + .text_input(cx, ids!(import_form.core.endpoint)) + .text(); + let url = + url::Url::parse(endpoint.trim()).map_err(|_| "Enter a complete Octos server URL")?; + if !matches!(url.scheme(), "http" | "https") + || url.host_str().is_none() + || !url.username().is_empty() + || url.password().is_some() + { + return Err("Use an HTTP or HTTPS URL without embedded credentials".into()); + } + let profile = self + .view + .text_input(cx, ids!(import_form.core.profile)) + .text(); + if profile.trim().is_empty() { + return Err("Enter the Octos profile name".into()); + } + let token = self + .view + .text_input(cx, ids!(import_form.core.token)) + .text(); + let provider = KernelProvider::connect(octos_app_transport::TransportConfig { + base_url: url, + bearer: octos_app_transport::SecretString::new(token), + profile_id: octos_app_transport::ProfileId::new(profile.trim()), + cursor: None, + cursor_file: None, + requested_capabilities: octos_app_transport::Capabilities::requested(), + workspace_cwd: None, + stdio: None, + })?; + self.connection_owner = Some(provider); + self.view + .text_input(cx, ids!(import_form.core.token)) + .set_text(cx, ""); + self.notice(cx, "Octos connection configured. Review and run your app."); + Ok(()) + } + fn review(&mut self, cx: &mut Cx) -> Result<(), String> { + self.stop(cx); + self.package = None; + let path = self.view.text_input(cx, ids!(path)).text(); + let snapshots = crate::app_data_dir().to_owned().join("miniapps/imports"); + let package = Package::load_in(&PathBuf::from(path.trim()), &snapshots)?; + let room = self.view.text_input(cx, ids!(room)).text(); + if !room.trim().is_empty() { + ruma::RoomId::parse(room.trim()).map_err(|_| "Invalid Matrix room ID")?; + } + let services = package.manifest.capabilities.join(", "); + self.notice(cx,&format!("{} {} · Local unsigned bundle\nServices: {}\nAllowed room: {}\nRun grants these services for this session. Octos turns may use the connected core's tools.",package.manifest.name,package.manifest.version,services,if room.trim().is_empty(){"None"}else{room.trim()})); + self.reviewed_room = room.trim().to_string(); + self.package = Some(package); + Ok(()) + } + fn run(&mut self, cx: &mut Cx) -> Result<(), String> { + self.stop(cx); + let package = self.package.as_ref().ok_or("Review a bundle first")?; + package.unchanged()?; + let account = crate::sliding_sync::current_user_id() + .ok_or("Log in to Matrix before running a mini app")? + .to_string(); + let room = self.view.text_input(cx, ids!(room)).text(); + if room.trim() != self.reviewed_room { + return Err("Room access changed. Review the bundle again".into()); + } + let room = if room.trim().is_empty() { + None + } else { + Some( + ruma::RoomId::parse(room.trim()) + .map_err(|_| "Invalid room ID")? + .to_string(), + ) + }; + static GENERATION: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(1); + let generation = GENERATION.fetch_add(1, std::sync::atomic::Ordering::Relaxed); + let lease = super::AUTHORITY.issue( + InstanceId { + app: package.manifest.id.clone(), + account: account.clone(), + room: room.clone(), + generation, + }, + package.manifest.capabilities.iter().cloned().collect(), + room.into_iter().collect(), + Instant::now() + Duration::from_secs(3600), + ); + self.tag = format!("rinx-miniapp-{generation}"); + self.data = package.data.clone(); + self.state = Default::default(); + if !package.script { + for (field, value) in octoscript_ui_l0::state_initials(&package.source) { + self.state + .set_cell(octoscript_ui_l0::CARD_STATE_KEY, &field, value); + } + } + let server = octosense_app_policy::AssetServer::start(&package.root)?; + octosense_app_policy::rewrite_assets(&mut self.data, server.origin()); + let account_dir: String = account.bytes().map(|b| format!("{b:02x}")).collect(); + // The local core's default read boundary is its data root. Allocate + // an account/app child there and then narrow the session to that child. + // The location comes from the native host, never from bundle input. + let root = octos_app_transport::shared::Connection::current() + .and_then(|c| c.local_data_root.clone()) + .unwrap_or_else(|| crate::app_data_dir().to_owned()) + .join("miniapps") + .join(account_dir); + let mut settings = package.policy.isolate_settings(&root); + std::fs::create_dir_all(&settings.jail_root).map_err(|e| e.to_string())?; + self.provider = + KernelProvider::shared(&settings.jail_root)?.map(|p| p as Arc); + settings.hosts.push(server.allowlist_entry()); + settings.allow_net = true; + if !package.script { + settings.capabilities.push("rinx.event".into()); + } + if !settings.capabilities.iter().any(|s| s == "net") { + settings.capabilities.push("net".into()); + } + let splash = self.view.splash(cx, ids!(card)); + octosense_app_policy::splash_adapter::apply(&splash, cx, &settings); + splash.set_host_tag(cx, Some(self.tag.clone())); + self.assets = Some(server); + self.lease = Some(lease); + self.render(cx)?; + let calls = self.package.as_ref().unwrap().bindings.on_open.clone(); + for call in calls { + self.binding(cx, call, "root", &Value::Null)?; + } + self.view.view(cx, ids!(import_form)).set_visible(cx, false); + self.notice( + cx, + "Running · Back closes this app and revokes its services.", + ); + Ok(()) + } + fn render(&mut self, cx: &mut Cx) -> Result<(), String> { + let package = self.package.as_ref().ok_or("No package")?; + if package.script { + let source = octosense_app_policy::script_source( + &package.root, + self.assets + .as_ref() + .ok_or("Missing bundle assets")? + .origin(), + ) + .ok_or("Missing main.splash")??; + self.view.splash(cx, ids!(card)).set_text(cx, &source); + return Ok(()); + } + let report = octoscript_ui_l0::realize_with_state( + &package.source, + &self.data, + &self.state, + Default::default(), + ); + report.complete_root()?; + self.state.prune(&report.live_keys); + for (field, value) in report.captured { + self.state + .set_cell(octoscript_ui_l0::CARD_STATE_KEY, &field, value); + } + let mut card = octoscript_makepad::l0::prepare_with_state( + &package.source, + &self.data, + &self.state, + &package.root.join("kit"), + )?; + octoscript_makepad::l0::inspectable(&mut card.tree); + let ui = if card.native_components { + octoscript_makepad::design::to_makepad_ui(&card.tree)? + } else { + octoscript_makepad::to_makepad_l0_ui(&card.tree) + }; + // NAV belongs to this isolate and enters the same authenticated queue + // as imperative host.request calls. No global Notify event is trusted. + let body = format!( + "let NAV = fn(t, v=\"\") {{ host.request(\"rinx.event\", {{route:t, value:v}}, fn(r){{}}) }}\nwidth:Fill height:Fill flow:Down\n{ui}" + ); + self.view.splash(cx, ids!(card)).reapply_text(cx, &body); + Ok(()) + } + fn dispatch( + &mut self, + service: &str, + args: Value, + reply: Option<(usize, u64)>, + target: Option, + ) -> Result<(), String> { + if target.is_some() && self.pending.iter().any(|p| p.target == target) { + return Err("This action is already running".into()); + } + if self.pending.len() >= 16 { + return Err("Mini app already has 16 pending requests".into()); + } + let lease = self.lease.clone().ok_or("Mini app is closed")?; + let account = crate::sliding_sync::current_user_id().ok_or("Not logged in")?; + lease.authorize(account.as_str(), service, None)?; + rinx_miniapp_core::parse_arguments(&args.to_string())?; + let (tx, rx) = mpsc::sync_channel(128); + if service.starts_with("matrix.") { + let service = service.to_owned(); + crate::sliding_sync::spawn_async_task(async move { + let result = super::matrix_request(lease, service, args).await; + let _ = tx.try_send(ServiceEvent::Complete(result)); + SignalToUI::set_ui_signal(); + }); + } else if service.starts_with("octos.") { + self.provider.as_ref().ok_or("Octos unavailable. Open AppCard in OctoSense to connect the core, then reopen this mini app.")?.request(lease,service,args,tx)?; + } else { + return Err(format!("No adapter for {service}")); + } + self.pending.push(Pending { + reply, + target, + receiver: rx, + started: Instant::now(), + turn: service == "octos.turn.start", + }); + Ok(()) + } + fn binding( + &mut self, + _cx: &mut Cx, + call: Call, + key: &str, + payload: &Value, + ) -> Result<(), String> { + let args = super::package::arguments(&call.args, &self.data, &self.state, key, payload)?; + self.dispatch(&call.service, args, None, Some(call.target)) + } + fn event(&mut self, cx: &mut Cx, args: Value) -> Result<(), String> { + let route = args["route"].as_str().ok_or("Missing event route")?; + let mut event: Value = serde_json::from_str( + route + .strip_prefix("l0:") + .ok_or("Unknown navigation event")?, + ) + .map_err(|e| e.to_string())?; + if event["v"] == "$$" { + event["v"] = args["value"].clone(); + } + let key = event["k"].as_str().ok_or("Missing instance key")?; + let name = event["e"].as_str().ok_or("Missing event name")?; + let package = self.package.as_ref().ok_or("No package")?; + if package.script { + return Err("L0 events are not available to main.splash apps".into()); + } + let changed = octoscript_ui_l0::dispatch_with_data( + &package.source, + &mut self.state, + key, + name, + Some(&event["v"]), + &self.data, + ); + let call = package.bindings.events.get(name).cloned(); + if changed { + self.render(cx)?; + } + if let Some(call) = call { + self.binding(cx, call, key, &event["v"])?; + } + Ok(()) + } + fn pump(&mut self, cx: &mut Cx) { + let Some(lease) = self.lease.clone() else { + return; + }; + if lease + .check( + &crate::sliding_sync::current_user_id() + .map(|u| u.to_string()) + .unwrap_or_default(), + ) + .is_err() + { + self.stop(cx); + self.notice(cx, "Session ended. Review and run again."); + return; + } + let heap = self.view.splash(cx, ids!(card)).isolate_heap_key(cx); + let owned_heaps: Vec<_> = heap.into_iter().collect(); + for req in take_splash_host_requests_for(&owned_heaps) { + let result = rinx_miniapp_core::parse_arguments(&req.args_json).and_then(|args| { + if req.service == "rinx.event" { + self.event(cx, args) + } else { + self.dispatch(&req.service, args, Some((req.heap_key, req.req_id)), None) + } + }); + if req.service == "rinx.event" || result.is_err() { + splash_host_respond( + cx, + req.heap_key, + req.req_id, + result.as_ref().map(|_| "{}").map_err(String::as_str), + ); + if let Err(e) = result { + self.notice(cx, &e); + } + } + } + let mut updates = Vec::new(); + self.pending.retain_mut(|pending| { + let mut done = false; + loop { + match pending.receiver.try_recv() { + Ok(event) => { + let complete = matches!(event, ServiceEvent::Complete(_)); + updates.push((pending.reply, pending.target.clone(), pending.turn, event)); + if complete { + done = true; + break; + } + } + Err(mpsc::TryRecvError::Empty) => break, + Err(mpsc::TryRecvError::Disconnected) => { + updates.push(( + pending.reply, + pending.target.clone(), + pending.turn, + ServiceEvent::Complete(Err( + "Service connection closed before completing".into(), + )), + )); + done = true; + break; + } + } + } + if !done && pending.started.elapsed() > Duration::from_secs(185) { + updates.push(( + pending.reply, + pending.target.clone(), + pending.turn, + ServiceEvent::Complete(Err("Service timed out".into())), + )); + done = true; + } + !done + }); + let mut redraw = false; + for (reply, target, turn, event) in updates { + let (complete, result) = match event { + ServiceEvent::Data(v) => (false, Ok(v)), + ServiceEvent::Complete(r) => (true, r), + }; + if !complete { + if let Ok(value) = &result { + let event = &value["event"]; + if event["kind"] == "approval_requested" { + if let Some(id) = event["approval_id"].as_str() { + if !self.approvals.iter().any(|a| a.id == id) { + self.approvals.push_back(Approval { + id: id.to_owned(), + message: format!( + "Octos tool approval: {}\n{}", + event["title"].as_str().unwrap_or("Tool request"), + event["body"].as_str().unwrap_or("") + ), + }); + } + self.show_approval(cx); + } + } + } + } + if let Some(target) = target { + let value = match &result { + Ok(v) => json!({"is_ok":true,"data":v}), + Err(e) => json!({"is_ok":false,"error":e}), + }; + self.data[&target] = value; + redraw = true; + } + if complete { + if turn { + self.approvals.clear(); + self.show_approval(cx); + } + if let Some((heap, req)) = reply { + let text = result.as_ref().map(|v| v.to_string()); + splash_host_respond(cx, heap, req, text.as_deref().map_err(|e| e.as_str())); + } + if let Err(error) = result { + self.notice(cx, &error); + } + } + } + if redraw { + if let Err(e) = self.render(cx) { + self.notice(cx, &e); + } + } + } +} +impl Widget for MiniAppsPanel { + fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope) { + if !self.open { + return; + } + self.view.handle_event(cx, event, scope); + if let Event::Actions(actions) = event { + if self.view.button(cx, ids!(close)).clicked(actions) { + cx.action(MiniAppsAction::Close); + } + let approve = self + .view + .button(cx, ids!(approval.buttons.allow)) + .clicked(actions); + let deny = self + .view + .button(cx, ids!(approval.buttons.deny)) + .clicked(actions); + if approve || deny { + if let (Some(approval), Some(provider), Some(lease)) = ( + self.approvals.pop_front(), + self.provider.clone(), + self.lease.clone(), + ) { + let (tx, rx) = mpsc::sync_channel(1); + match provider.decide(lease, &approval.id, approve, tx) { + Ok(()) => self.pending.push(Pending { + reply: None, + target: None, + receiver: rx, + started: Instant::now(), + turn: false, + }), + Err(e) => self.notice(cx, &e), + } + self.show_approval(cx); + } + } + let result = if self + .view + .button(cx, ids!(import_form.core.connect)) + .clicked(actions) + { + self.connect(cx) + } else if self.view.button(cx, ids!(review)).clicked(actions) { + self.review(cx) + } else if self.view.button(cx, ids!(run)).clicked(actions) { + self.run(cx) + } else { + Ok(()) + }; + if let Err(e) = result { + self.stop(cx); + self.notice(cx, &e); + } + } + if let Event::BackPressed { handled } = event { + handled.set(true); + cx.action(MiniAppsAction::Close); + } + self.pump(cx); + } + fn draw_walk(&mut self, cx: &mut Cx2d, scope: &mut Scope, walk: Walk) -> DrawStep { + self.view.draw_walk(cx, scope, walk) + } +} +impl MiniAppsPanelRef { + pub fn action(&self, cx: &mut Cx, modal: ModalRef, action: &MiniAppsAction) { + if let Some(mut inner) = self.borrow_mut() { + match action { + MiniAppsAction::Open => { + inner.open = true; + inner.notice(cx, "Import an OctoSense bundle to review its services."); + #[cfg(feature = "octosense-module")] + inner + .view + .view(cx, ids!(import_form.core)) + .set_visible(cx, !crate::module::is_hosted()); + modal.open(cx); + } + MiniAppsAction::Close => { + inner.stop(cx); + inner.open = false; + modal.close(cx); + } + } + } + } +} diff --git a/src/settings/app_preferences.rs b/src/settings/app_preferences.rs index 0fc61794..beef47a6 100644 --- a/src/settings/app_preferences.rs +++ b/src/settings/app_preferences.rs @@ -174,6 +174,7 @@ impl AppPreferences { /// Applies the current `show_read_receipts` value. pub fn on_show_read_receipts_changed(&self, cx: &mut Cx) { cx.global::().0.show_read_receipts = self.show_read_receipts; + SHOW_READ_RECEIPTS.store(self.show_read_receipts, Ordering::Relaxed); // Read receipt avatar rows check this pref at draw time, so redraw everything. cx.redraw_all(); } @@ -332,6 +333,9 @@ impl MarkAsReadBehavior { } /// A way to allow `read_receipts_privacy` to be accessed by all threads. +static SHOW_READ_RECEIPTS: AtomicBool = AtomicBool::new(true); +pub fn show_read_receipts() -> bool { SHOW_READ_RECEIPTS.load(Ordering::Relaxed) } + static SEND_PUBLIC_READ_RECEIPTS: AtomicBool = AtomicBool::new(true); /// Returns the user's current preference of read receipt type. diff --git a/src/sliding_sync.rs b/src/sliding_sync.rs index 8b9fa593..fa80ac8b 100644 --- a/src/sliding_sync.rs +++ b/src/sliding_sync.rs @@ -3490,6 +3490,7 @@ async fn start_matrix_client_login_and_sync(rt: Handle) { // Store this active client in our global Client state so that other tasks can access it. crate::article_app::invalidate_sessions(); + crate::octoscript_apps::invalidate_sessions(); if let Some(_existing) = CLIENT.lock().unwrap().replace(client.clone()) { error!("BUG: unexpectedly replaced an existing client when initializing the matrix client."); } @@ -3537,6 +3538,7 @@ async fn start_matrix_client_login_and_sync(rt: Handle) { // Clear the stored client so the next login attempt doesn't trigger the // "unexpectedly replaced an existing client" warning. crate::article_app::invalidate_sessions(); + crate::octoscript_apps::invalidate_sessions(); let _ = CLIENT.lock().unwrap().take(); abort_and_await_handles(&mut subscriber_task_handles).await; continue 'login_loop; @@ -3691,6 +3693,7 @@ async fn start_matrix_client_login_and_sync(rt: Handle) { } // No-ops if `clear_app_state` already cleared these. crate::article_app::invalidate_sessions(); + crate::octoscript_apps::invalidate_sessions(); let _ = CLIENT.lock().unwrap().take(); let _ = SYNC_SERVICE.lock().unwrap().take(); SYNC_SERVICE_ASSUMED_RUNNING.store(false, Ordering::Release); @@ -5950,6 +5953,7 @@ impl UserPowerLevels { /// which needs to keep running to receive the next login request. pub async fn clear_app_state(config: &LogoutConfig) -> Result<()> { crate::article_app::invalidate_sessions(); + crate::octoscript_apps::invalidate_sessions(); CLIENT.lock().unwrap().take(); SYNC_SERVICE.lock().unwrap().take(); SYNC_SERVICE_ASSUMED_RUNNING.store(false, Ordering::Release); diff --git a/tools/miniapp-package/Cargo.lock b/tools/miniapp-package/Cargo.lock new file mode 100644 index 00000000..344a05a4 --- /dev/null +++ b/tools/miniapp-package/Cargo.lock @@ -0,0 +1,185 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "arrayvec" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56" + +[[package]] +name = "blake3" +version = "1.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d9e454fc11f76977dc803893aff6304ed33d6a26efae8696573bea74baa27ae" +dependencies = [ + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", + "cpufeatures", +] + +[[package]] +name = "cc" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f360145194ee8e21db5ee7f3fcd4fe52210864c75c985dae33218202c8bbe040" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600" + +[[package]] +name = "constant_time_eq" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b" + +[[package]] +name = "cpufeatures" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca28b0ae3115b884660db4118d803791fd6756b6e88f39c0f3f7859060d7566" +dependencies = [ + "libc", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aedcfb3409746eddb02b9e19ebda1c3394f759a152e48ee875a0844d1b955484" + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "libc" +version = "0.2.189" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" + +[[package]] +name = "memchr" +version = "2.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" + +[[package]] +name = "octosense-app-policy" +version = "0.1.0" +source = "git+https://github.com/OctoSense-org/OctoSense-App-Hub.git?rev=b0591e2caa0dc5c62927f7b85dbf826a50618a03#b0591e2caa0dc5c62927f7b85dbf826a50618a03" +dependencies = [ + "blake3", + "serde", + "serde_json", +] + +[[package]] +name = "proc-macro2" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rinx-miniapp-package" +version = "0.1.0" +dependencies = [ + "octosense-app-policy", + "serde_json", +] + +[[package]] +name = "serde" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.151" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "shlex" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" + +[[package]] +name = "syn" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8593e8e72159ed2257d083c7a454a85cbf854f37a0966d8d483aff8c8a3ebcee" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d245f478577f809a851594d02313b640fb437e0bb33866753cff937863096954" + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/tools/miniapp-package/Cargo.toml b/tools/miniapp-package/Cargo.toml new file mode 100644 index 00000000..4861e9e9 --- /dev/null +++ b/tools/miniapp-package/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "rinx-miniapp-package" +version = "0.1.0" +edition = "2024" +[workspace] +[dependencies] +octosense-app-policy = { git = "https://github.com/OctoSense-org/OctoSense-App-Hub.git", rev = "b0591e2caa0dc5c62927f7b85dbf826a50618a03" } +serde_json = "1" diff --git a/tools/miniapp-package/src/main.rs b/tools/miniapp-package/src/main.rs new file mode 100644 index 00000000..5b79bf1a --- /dev/null +++ b/tools/miniapp-package/src/main.rs @@ -0,0 +1,27 @@ +//! Refresh a local unsigned OctoSense bundle digest after editing its sources. +fn main() -> Result<(), Box> { + let dir = std::path::PathBuf::from( + std::env::args_os() + .nth(1) + .ok_or("Usage: rinx-miniapp-package BUNDLE_DIR")?, + ); + let path = dir.join("manifest.json"); + let mut manifest: serde_json::Value = serde_json::from_str(&std::fs::read_to_string(&path)?)?; + if !manifest["integrity"]["signature"].is_null() { + return Err("This tool does not modify signed manifests".into()); + } + let digest = octosense_app_policy::digest_dir(&dir)?; + manifest["integrity"]["bundle_blake3"] = digest.into(); + let json = serde_json::to_string_pretty(&manifest)?; + let parsed = octosense_app_policy::AppManifest::parse(&json)?; + octosense_app_policy::policy::resolve( + &parsed, + &octosense_app_policy::HostLimits { + require_signature: false, + ..Default::default() + }, + )?; + std::fs::write(&path, json + "\n")?; + println!("Packaged {} {}", parsed.id, parsed.version); + Ok(()) +} From ba5cd50e320742339806712d48dea2901dff3318 Mon Sep 17 00:00:00 2001 From: ymote <151983+ymote@users.noreply.github.com> Date: Sat, 26 Sep 2026 10:11:04 -0700 Subject: [PATCH 02/10] Refresh standalone article lockfiles for the shared runtime pin --- crates/article-core/Cargo.lock | 2 +- crates/article-makepad/Cargo.lock | 242 +++++++++++++++--------------- 2 files changed, 122 insertions(+), 122 deletions(-) diff --git a/crates/article-core/Cargo.lock b/crates/article-core/Cargo.lock index 0428dc8b..c2ede1a7 100644 --- a/crates/article-core/Cargo.lock +++ b/crates/article-core/Cargo.lock @@ -398,7 +398,7 @@ checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6" [[package]] name = "makepad-markdown" version = "0.1.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "blake3", "comrak", diff --git a/crates/article-makepad/Cargo.lock b/crates/article-makepad/Cargo.lock index 55d4a620..8c2b3cbd 100644 --- a/crates/article-makepad/Cargo.lock +++ b/crates/article-makepad/Cargo.lock @@ -5,7 +5,7 @@ version = 4 [[package]] name = "ab_glyph_rasterizer" version = "0.1.8" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "adler2" @@ -43,7 +43,7 @@ checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" [[package]] name = "arrayvec" version = "0.7.6" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "arrayvec" @@ -80,7 +80,7 @@ dependencies = [ [[package]] name = "ash" version = "0.38.0+1.3.281" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "libloading 0.8.9", ] @@ -118,9 +118,9 @@ dependencies = [ [[package]] name = "bit-set" version = "0.8.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ - "bit-vec 0.8.0 (git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4)", + "bit-vec 0.8.0 (git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", ] [[package]] @@ -132,7 +132,7 @@ checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" [[package]] name = "bit-vec" version = "0.8.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "bitflags" @@ -143,7 +143,7 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" version = "2.10.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "bitflags" @@ -167,7 +167,7 @@ dependencies = [ [[package]] name = "bytemuck" version = "1.25.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "bytemuck" @@ -178,7 +178,7 @@ checksum = "95832e849adfb21180ccb6826a99da14e5d266ae5c2e668e1602cf234f153797" [[package]] name = "byteorder" version = "1.5.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "byteorder-lite" @@ -214,12 +214,12 @@ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "cfg-if" version = "1.0.4" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "cfg_aliases" version = "0.2.1" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "color_quant" @@ -305,7 +305,7 @@ dependencies = [ [[package]] name = "crunchy" version = "0.2.4" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "ctor" @@ -337,7 +337,7 @@ dependencies = [ [[package]] name = "downcast-rs" version = "1.2.1" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "emojis" @@ -363,7 +363,7 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "equivalent" version = "1.0.2" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "euclid" @@ -443,7 +443,7 @@ checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" [[package]] name = "foldhash" version = "0.2.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "fontconfig-parser" @@ -480,7 +480,7 @@ dependencies = [ [[package]] name = "fxhash" version = "0.2.1" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "byteorder", ] @@ -557,15 +557,15 @@ dependencies = [ [[package]] name = "hashbrown" version = "0.16.1" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ - "foldhash 0.2.0 (git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4)", + "foldhash 0.2.0 (git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", ] [[package]] name = "hexf-parse" version = "0.2.1" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "hilog-sys" @@ -724,10 +724,10 @@ checksum = "09e54e57b4c48b40f7aec75635392b12b3421fa26fe8b4332e63138ed278459c" [[package]] name = "indexmap" version = "2.13.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ - "equivalent 1.0.2 (git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4)", - "hashbrown 0.16.1 (git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4)", + "equivalent 1.0.2 (git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", + "hashbrown 0.16.1 (git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", ] [[package]] @@ -783,9 +783,9 @@ dependencies = [ [[package]] name = "libloading" version = "0.8.9" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ - "cfg-if 1.0.4 (git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4)", + "cfg-if 1.0.4 (git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", "windows-link 0.2.1", ] @@ -837,7 +837,7 @@ dependencies = [ [[package]] name = "makepad-apple-sys" version = "1.0.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "makepad-objc-sys", ] @@ -845,12 +845,12 @@ dependencies = [ [[package]] name = "makepad-byteorder-lite" version = "0.1.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "makepad-derive-wasm-bridge" version = "1.0.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "makepad-micro-proc-macro", ] @@ -858,7 +858,7 @@ dependencies = [ [[package]] name = "makepad-derive-widget" version = "2.0.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "makepad-live-id", "makepad-micro-proc-macro", @@ -867,7 +867,7 @@ dependencies = [ [[package]] name = "makepad-draw" version = "2.0.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "ab_glyph_rasterizer", "fxhash", @@ -885,7 +885,7 @@ dependencies = [ "sdfer", "serde", "ttf-parser 0.24.1", - "unicode-bidi 0.3.18 (git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4)", + "unicode-bidi 0.3.18 (git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", "unicode-linebreak", "unicode-segmentation 1.12.0", ] @@ -893,7 +893,7 @@ dependencies = [ [[package]] name = "makepad-error-log" version = "1.0.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "makepad-micro-serde", ] @@ -901,12 +901,12 @@ dependencies = [ [[package]] name = "makepad-fast-inflate" version = "0.1.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "makepad-filesystem-watcher" version = "0.1.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "makepad-git", ] @@ -914,25 +914,25 @@ dependencies = [ [[package]] name = "makepad-futures" version = "1.0.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "makepad-futures-legacy" version = "1.0.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "makepad-gif" version = "0.1.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ - "weezl 0.1.12 (git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4)", + "weezl 0.1.12 (git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", ] [[package]] name = "makepad-git" version = "0.1.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "makepad-fast-inflate", ] @@ -940,9 +940,9 @@ dependencies = [ [[package]] name = "makepad-half" version = "2.7.1" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ - "cfg-if 1.0.4 (git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4)", + "cfg-if 1.0.4 (git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", "crunchy", "num-traits 0.2.20", "zerocopy 0.8.39", @@ -951,7 +951,7 @@ dependencies = [ [[package]] name = "makepad-html" version = "1.0.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "makepad-live-id", ] @@ -965,7 +965,7 @@ checksum = "9775cbec5fa0647500c3e5de7c850280a88335d1d2d770e5aa2332b801ba7064" [[package]] name = "makepad-latex-math" version = "0.1.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "ttf-parser 0.24.1", ] @@ -973,7 +973,7 @@ dependencies = [ [[package]] name = "makepad-live-id" version = "1.0.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "makepad-live-id-macros", "serde", @@ -982,7 +982,7 @@ dependencies = [ [[package]] name = "makepad-live-id-macros" version = "1.0.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "makepad-micro-proc-macro", ] @@ -990,7 +990,7 @@ dependencies = [ [[package]] name = "makepad-live-reload-core" version = "0.1.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "makepad-filesystem-watcher", ] @@ -998,7 +998,7 @@ dependencies = [ [[package]] name = "makepad-markdown" version = "0.1.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "blake3", "comrak", @@ -1012,7 +1012,7 @@ dependencies = [ [[package]] name = "makepad-markdown-widgets" version = "0.1.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "blake3", "core-foundation", @@ -1032,7 +1032,7 @@ dependencies = [ [[package]] name = "makepad-math" version = "1.0.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "makepad-micro-serde", ] @@ -1040,12 +1040,12 @@ dependencies = [ [[package]] name = "makepad-micro-proc-macro" version = "1.0.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "makepad-micro-serde" version = "1.0.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "makepad-live-id", "makepad-micro-serde-derive", @@ -1054,7 +1054,7 @@ dependencies = [ [[package]] name = "makepad-micro-serde-derive" version = "1.0.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "makepad-micro-proc-macro", ] @@ -1062,7 +1062,7 @@ dependencies = [ [[package]] name = "makepad-network" version = "1.0.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "makepad-apple-sys", "makepad-error-log", @@ -1076,12 +1076,12 @@ dependencies = [ [[package]] name = "makepad-objc-sys" version = "1.0.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "makepad-platform" version = "2.0.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "ash", "bitflags 2.10.0", @@ -1107,7 +1107,7 @@ dependencies = [ "napi-ohos", "ohos-sys", "rqrr", - "smallvec 1.15.1 (git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4)", + "smallvec 1.15.1 (git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", "wayland-client", "wayland-egl", "wayland-protocols", @@ -1119,7 +1119,7 @@ dependencies = [ [[package]] name = "makepad-platform-video" version = "1.0.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "makepad-apple-sys", "makepad-objc-sys", @@ -1129,12 +1129,12 @@ dependencies = [ [[package]] name = "makepad-regex" version = "0.1.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "makepad-script" version = "1.0.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "makepad-error-log", "makepad-html", @@ -1143,13 +1143,13 @@ dependencies = [ "makepad-regex", "makepad-script-derive", "makepad-stitch", - "smallvec 1.15.1 (git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4)", + "smallvec 1.15.1 (git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", ] [[package]] name = "makepad-script-derive" version = "1.0.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "makepad-micro-proc-macro", ] @@ -1157,7 +1157,7 @@ dependencies = [ [[package]] name = "makepad-script-std" version = "1.0.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "makepad-network", "makepad-script", @@ -1166,17 +1166,17 @@ dependencies = [ [[package]] name = "makepad-shared-bytes" version = "1.0.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "makepad-stitch" version = "0.1.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "makepad-studio-protocol" version = "0.1.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "bitflags 2.10.0", "makepad-error-log", @@ -1188,7 +1188,7 @@ dependencies = [ [[package]] name = "makepad-svg" version = "1.0.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "makepad-html", "makepad-live-id", @@ -1197,7 +1197,7 @@ dependencies = [ [[package]] name = "makepad-tsdf" version = "0.1.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "makepad-math", "makepad-micro-serde", @@ -1206,7 +1206,7 @@ dependencies = [ [[package]] name = "makepad-wasm-bridge" version = "1.0.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "makepad-derive-wasm-bridge", "makepad-live-id", @@ -1215,7 +1215,7 @@ dependencies = [ [[package]] name = "makepad-webp" version = "0.2.4" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "makepad-byteorder-lite", ] @@ -1223,7 +1223,7 @@ dependencies = [ [[package]] name = "makepad-widgets" version = "2.0.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "makepad-derive-widget", "makepad-draw", @@ -1240,7 +1240,7 @@ dependencies = [ [[package]] name = "makepad-zune-bmp" version = "0.5.2" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "makepad-error-log", "makepad-zune-core", @@ -1249,7 +1249,7 @@ dependencies = [ [[package]] name = "makepad-zune-core" version = "0.5.1" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "makepad-error-log", ] @@ -1257,7 +1257,7 @@ dependencies = [ [[package]] name = "makepad-zune-inflate" version = "0.2.54" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "simd-adler32 0.3.9", ] @@ -1265,7 +1265,7 @@ dependencies = [ [[package]] name = "makepad-zune-jpeg" version = "0.5.15" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "makepad-zune-core", ] @@ -1273,7 +1273,7 @@ dependencies = [ [[package]] name = "makepad-zune-png" version = "0.5.2" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "makepad-fast-inflate", "makepad-zune-core", @@ -1283,7 +1283,7 @@ dependencies = [ [[package]] name = "makepad-zune-qoi" version = "0.5.2" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "makepad-zune-core", ] @@ -1308,7 +1308,7 @@ checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "memchr" version = "2.7.6" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "memmap2" @@ -1359,14 +1359,14 @@ dependencies = [ [[package]] name = "naga" version = "27.0.3" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "arrayvec 0.7.6", - "bit-set 0.8.0 (git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4)", + "bit-set 0.8.0 (git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", "bitflags 2.10.0", - "cfg-if 1.0.4 (git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4)", + "cfg-if 1.0.4 (git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", "cfg_aliases", - "hashbrown 0.16.1 (git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4)", + "hashbrown 0.16.1 (git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", "hexf-parse", "indexmap", "makepad-error-log", @@ -1446,7 +1446,7 @@ dependencies = [ [[package]] name = "num-traits" version = "0.2.20" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "octoscript-node" @@ -1462,7 +1462,7 @@ checksum = "8d380ab6c951261a0e44306245bc960b3b3367f099a7da7156bd1a3cacaf783c" [[package]] name = "once_cell" version = "1.21.3" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "once_cell" @@ -1547,7 +1547,7 @@ checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" [[package]] name = "pkg-config" version = "0.3.32" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "png" @@ -1620,10 +1620,10 @@ dependencies = [ [[package]] name = "pulldown-cmark" version = "0.12.2" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "bitflags 2.10.0", - "memchr 2.7.6 (git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4)", + "memchr 2.7.6 (git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", "unicase 2.9.0", ] @@ -1790,7 +1790,7 @@ dependencies = [ [[package]] name = "rustc-hash" version = "1.1.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "rustc-hash" @@ -1801,17 +1801,17 @@ checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d" [[package]] name = "rustybuzz" version = "0.18.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "bitflags 2.10.0", "bytemuck 1.25.0", "makepad-error-log", - "smallvec 1.15.1 (git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4)", + "smallvec 1.15.1 (git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", "ttf-parser 0.24.1", "unicode-bidi-mirroring 0.3.0", "unicode-ccc 0.3.0", - "unicode-properties 0.1.4 (git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4)", - "unicode-script 0.5.8 (git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4)", + "unicode-properties 0.1.4 (git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", + "unicode-script 0.5.8 (git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", ] [[package]] @@ -1844,7 +1844,7 @@ dependencies = [ [[package]] name = "scoped-tls" version = "1.0.1" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "scopeguard" @@ -1855,7 +1855,7 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "sdfer" version = "0.2.1" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "serde" @@ -1909,7 +1909,7 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "simd-adler32" version = "0.3.9" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "simd-adler32" @@ -1950,12 +1950,12 @@ checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "smallvec" version = "1.15.1" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "spirv" version = "0.3.0+sdk-1.3.268.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "bitflags 2.10.0", ] @@ -2072,7 +2072,7 @@ dependencies = [ [[package]] name = "thiserror" version = "2.0.18" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "thiserror-impl 2.0.18", ] @@ -2089,7 +2089,7 @@ dependencies = [ [[package]] name = "thiserror-impl" version = "2.0.18" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "makepad-micro-proc-macro", ] @@ -2150,7 +2150,7 @@ checksum = "fd3ca314f692efd6c868f8408f53fe444634a845f96c028b97d35f6a1f79f0ee" [[package]] name = "ttf-parser" version = "0.24.1" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "ttf-parser" @@ -2182,7 +2182,7 @@ checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" [[package]] name = "unicase" version = "2.9.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "unicode-bidi" @@ -2193,12 +2193,12 @@ checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" [[package]] name = "unicode-bidi" version = "0.3.18" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "unicode-bidi-mirroring" version = "0.3.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "unicode-bidi-mirroring" @@ -2209,7 +2209,7 @@ checksum = "5dfa6e8c60bb66d49db113e0125ee8711b7647b5579dc7f5f19c42357ed039fe" [[package]] name = "unicode-ccc" version = "0.3.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "unicode-ccc" @@ -2226,12 +2226,12 @@ checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" [[package]] name = "unicode-ident" version = "1.0.22" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "unicode-linebreak" version = "0.1.5" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "unicode-normalization" @@ -2251,7 +2251,7 @@ checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" [[package]] name = "unicode-properties" version = "0.1.4" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "unicode-script" @@ -2262,12 +2262,12 @@ checksum = "383ad40bb927465ec0ce7720e033cb4ca06912855fc35db31b5755d0de75b1ee" [[package]] name = "unicode-script" version = "0.5.8" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "unicode-segmentation" version = "1.12.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "unicode-segmentation" @@ -2357,7 +2357,7 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wayland-backend" version = "0.3.12" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "downcast-rs", "scoped-tls", @@ -2368,7 +2368,7 @@ dependencies = [ [[package]] name = "wayland-client" version = "0.31.12" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "bitflags 2.10.0", "wayland-backend", @@ -2378,7 +2378,7 @@ dependencies = [ [[package]] name = "wayland-egl" version = "0.32.9" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "wayland-backend", "wayland-sys", @@ -2387,7 +2387,7 @@ dependencies = [ [[package]] name = "wayland-protocols" version = "0.32.10" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "bitflags 2.10.0", "wayland-backend", @@ -2397,7 +2397,7 @@ dependencies = [ [[package]] name = "wayland-sys" version = "0.31.8" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "makepad-error-log", "pkg-config", @@ -2424,7 +2424,7 @@ checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88" [[package]] name = "weezl" version = "0.1.12" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "winapi-util" @@ -2438,7 +2438,7 @@ dependencies = [ [[package]] name = "windows" version = "0.62.2" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "windows-collections", "windows-core", @@ -2448,7 +2448,7 @@ dependencies = [ [[package]] name = "windows-collections" version = "0.3.2" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "windows-core", ] @@ -2456,7 +2456,7 @@ dependencies = [ [[package]] name = "windows-core" version = "0.62.2" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "windows-link 0.2.1", "windows-result", @@ -2466,7 +2466,7 @@ dependencies = [ [[package]] name = "windows-future" version = "0.3.2" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "windows-core", ] @@ -2480,12 +2480,12 @@ checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" [[package]] name = "windows-link" version = "0.2.1" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "windows-result" version = "0.4.1" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "windows-link 0.2.1", ] @@ -2493,7 +2493,7 @@ dependencies = [ [[package]] name = "windows-strings" version = "0.5.1" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" dependencies = [ "windows-link 0.2.1", ] @@ -2684,7 +2684,7 @@ dependencies = [ [[package]] name = "zerocopy" version = "0.8.39" -source = "git+https://github.com/OctoSense-org/makepad?rev=1d3d383e84a66dbb18a4a860f505430c9d5b20f4#1d3d383e84a66dbb18a4a860f505430c9d5b20f4" +source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" [[package]] name = "zerocopy-derive" From d2469eabd7b2a582fab68192202af540f40f1168 Mon Sep 17 00:00:00 2001 From: ymote <151983+ymote@users.noreply.github.com> Date: Sat, 26 Sep 2026 13:28:15 -0700 Subject: [PATCH 03/10] Fix late Octos stream fragments duplicating saved answers --- .../0005-octoscript-miniapps-matrix-octos.md | 12 ++-- src/octoscript_apps/octos.rs | 71 +++++++++++++++++++ 2 files changed, 78 insertions(+), 5 deletions(-) diff --git a/docs/adr/0005-octoscript-miniapps-matrix-octos.md b/docs/adr/0005-octoscript-miniapps-matrix-octos.md index aa212fc0..12aee5af 100644 --- a/docs/adr/0005-octoscript-miniapps-matrix-octos.md +++ b/docs/adr/0005-octoscript-miniapps-matrix-octos.md @@ -1,7 +1,7 @@ # ADR 0005: Octoscript mini apps with Matrix and Octos services - Date: 2026-09-26 -- Status: Accepted; implemented and natively verified, with live model generation blocked by provider authentication +- Status: Accepted; implemented and natively verified, including live model generation on macOS and Android - Supersedes the general-runtime deferral in ADR 0002. The article editor and its grants remain supported. ## Outcome @@ -80,19 +80,21 @@ Remote `main` was checked again at 10:37 UTC: desktop `57f4665c` and ROM Home `5 | Check | Result | | --- | --- | | Portable request parsing, grants, account/room isolation and revocation | 30 tests pass | -| Rinx bundle admission, state updates, stream isolation and turn IDs | 7 tests pass | +| Rinx bundle admission, state updates, stream isolation and turn IDs | 8 tests pass, including persisted answers arriving before the last deltas | | Shared transport, correlated replies and local storage configuration | 33 tests pass | | AppCard store/render and remaining workspace tests | 45 tests pass; one transport doc test ignored | | AppCard main library suite | 191 pass, 7 fail, 3 ignored; identical failures reproduced from clean `4d99cb5` app sources against the locked framework sources | | AppCard workspace check and clippy (`--all-targets --no-deps -- -D warnings`) | Pass | | Desktop native mini apps | Both bundle formats render; live Matrix profile and Octos session open/history work; continuous Chinese/emoji input, close/reopen, and one shared core process verified | | Android native mini apps | Both bundle formats render; live Matrix profile, Octos session open/history, continuous input, keyboard dismissal and close/reopen work. A Back key and an actual system edge swipe each return to Rinx Discover without exiting Rinx; one shared core process verified | -| Live model generation | Not passed: the configured DeepSeek provider returns HTTP 401. No generated answer or tool-approval success is claimed | +| Live model generation | Pass after updating the private test credentials: both L0 and `main.splash` mini apps receive real DeepSeek answers on macOS and Android through the shared AppCard core. Native tool approvals remain unverified | The seven baseline AppCard failures concern L0 exemplar/capability/theme drift: `every_call_the_lowering_emits_has_a_helper`, `the_nav_exemplar_is_the_card_the_profile_tests_check`, `l0_theme_axes_are_all_answered`, `a_live_source_without_its_capability_is_visibly_wrong`, `a_watch_row_reveals_its_own_remove`, `nav_is_generated_from_an_l0_spec`, and `the_language_reference_lists_every_admitted_theme`. They are not suppressed or weakened by this change. Native verification caught and fixed lost generated-label updates, missing font fallback in L0 inputs, the core profile's rejection of a workspace outside its read allowlist, and two Android Back deliveries from one key press. Parallel import tests caught a timestamp collision: admitted snapshots now use UUID names, and failed directory creation cannot acquire cleanup ownership over an existing snapshot. +The live-generation follow-up caught a response-ordering race on Android: a complete `assistant_persisted` answer arrived before the final streaming fragments for the same segment. Rinx now treats that saved answer as authoritative and ignores later deltas for that segment, including when a newer segment has begun. A regression test reproduces this ordering. The rebuilt phone app displayed both generated answers exactly as saved by the core, with one shared core process. On macOS, changing the L0 prompt to ask 17 + 25 returned `42`; the script bundle also received a real answer. Credentials remain outside the repositories. + The phone's installed base image is `octosense-202609240442`, matching the latest local OTA in `rom-builds/20260924-display` (Android 15 / SDK 35). This work installs current ROM Home application code as `dev.makepad.octosense.rinx`; it does not flash a new system image or replace the normal `dev.makepad.octosense` launcher. Standalone Rinx is build-checked; its remote-provider UI has not been exercised against a separate live server. Write-side Matrix calls and native tool approvals were not exercised against live services. ### Final validation artifacts @@ -102,9 +104,9 @@ Both release builds passed and were exercised natively. Paths below are relative | Artifact | Path | SHA-256 | | --- | --- | --- | | macOS executable | `OctoSense/target/release/octosense` | `d3321ce95393c5b606d67b56af932f15aa63e444cef5bdcaee399d7fa77440d5` | -| Android test APK | `OctoSense-ROM-rinx-latest/home/target/android/makepad-android-apk/octosense/apk/octo_senserinx.apk` | `9ebd5487876252695d2a365b70d7c02207617d2cc64979cd8b34386cd19585a8` | +| Android test APK, response-ordering follow-up | `OctoSense-ROM-rinx-latest/home/target/android/makepad-android-apk/octosense/apk/octo_senserinx.apk` | `a74091a6bb4857533aa37b6ea34a152807e88d7d4536ce0e2e63139284f1aadc` | -The owned desktop and phone test instances were closed after validation. The Android test APK remains installed for manual testing. The coordinated commits and PRs below publish the tested implementation. Dependency source identities and lockfiles were normalized after native validation; the recorded binary hashes identify the preceding native test builds. +The owned desktop and phone test instances were closed after validation. The Android test APK remains installed for manual testing. The coordinated commits and PRs below publish the tested implementation. Dependency source identities and lockfiles were normalized after the initial native validation. The Android follow-up used the published dependency pins and a temporary local Rinx override for the response-ordering fix; the macOS artifact predates that fix. Native test builds also include the developer checkout's unrelated homeserver timeout change, which is excluded from this PR. ### Published dependency commits diff --git a/src/octoscript_apps/octos.rs b/src/octoscript_apps/octos.rs index 61259fd1..15f583ef 100644 --- a/src/octoscript_apps/octos.rs +++ b/src/octoscript_apps/octos.rs @@ -238,6 +238,7 @@ struct TurnReply { text: String, segment: String, sequence: std::collections::BTreeMap, + persisted_segments: std::collections::BTreeSet, v2: bool, completed: bool, } @@ -269,6 +270,15 @@ impl TurnReply { match payload["type"].as_str().unwrap_or("") { "assistant_delta" | "assistant_persisted" => { let segment = data["assistant_segment_id"].as_str().unwrap_or(""); + // Persistence and live deltas travel on separate core + // lanes. A complete saved answer may precede higher- + // sequence deltas for the same segment; those fragments + // are already included in the saved text. + if payload["type"] == "assistant_delta" + && self.persisted_segments.contains(segment) + { + return Ok(false); + } if !self.v2 || self.segment != segment { self.text.clear(); self.segment = segment.into(); @@ -276,6 +286,7 @@ impl TurnReply { self.v2 = true; let text = data["text"].as_str().unwrap_or(""); if payload["type"] == "assistant_persisted" { + self.persisted_segments.insert(segment.to_owned()); self.text = text.into(); } else { self.text.push_str(text); @@ -309,6 +320,66 @@ impl TurnReply { #[cfg(test)] mod tests { use super::*; + #[test] + fn persisted_answers_ignore_late_deltas_without_blocking_new_segments() { + let mut reply = TurnReply::default(); + let event = |seq, kind, segment, text| { + json!({"kind":"envelope_v2","envelope":{ + "turn_id":"owned","thread_id":"thread","seq":seq, + "payload":{"type":kind,"data":{ + "assistant_segment_id":segment,"text":text + }} + }}) + }; + reply + .accept("owned", &event(1, "assistant_delta", "first", "Hello")) + .unwrap(); + reply + .accept( + "owned", + &event(2, "assistant_persisted", "first", "Hello! How can I help?"), + ) + .unwrap(); + assert!( + !reply + .accept( + "owned", + &event(3, "assistant_delta", "first", "! How can I help?") + ) + .unwrap() + ); + assert_eq!(reply.text, "Hello! How can I help?"); + assert!( + reply + .accept( + "owned", + &event(4, "assistant_delta", "next", "Another answer") + ) + .unwrap() + ); + assert!( + !reply + .accept( + "owned", + &event(5, "assistant_delta", "first", "late old fragment") + ) + .unwrap() + ); + assert_eq!(reply.text, "Another answer"); + reply + .accept( + "owned", + &event(6, "assistant_persisted", "next", "Another answer."), + ) + .unwrap(); + assert!( + !reply + .accept("owned", &event(7, "assistant_delta", "next", ".")) + .unwrap() + ); + assert_eq!(reply.text, "Another answer."); + } + #[test] fn v2_final_replaces_deltas_and_ignores_other_turns_and_replay() { let mut reply = TurnReply::default(); From 706c83ade1c9650c78a712d217e1833532201197 Mon Sep 17 00:00:00 2001 From: ymote <151983+ymote@users.noreply.github.com> Date: Sat, 26 Sep 2026 14:50:15 -0700 Subject: [PATCH 04/10] Keep compact article editor controls inside their header --- src/article_app/ui.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/article_app/ui.rs b/src/article_app/ui.rs index 82be6df1..0ee18b46 100644 --- a/src/article_app/ui.rs +++ b/src/article_app/ui.rs @@ -111,7 +111,7 @@ script_mod! { use mod.prelude.widgets.* use mod.widgets.* mod.widgets.ArticleLabel = Label {width: Fill height: Fit flow: Flow.Right{wrap: true} draw_text +: {color: #x191919 text_style: theme.font_regular{font_size: 13}}} - mod.widgets.ArticleButton = RobrixNeutralIconButton {grab_key_focus: false height: 42 padding: Inset{left: 12 right: 12} draw_text +: {color: #x333333 text_style: theme.font_regular{font_size: 12}} draw_bg +: {color: #xffffff color_hover: #xf2f5f3 color_down: #xe7f2e9 border_radius: 6}} + mod.widgets.ArticleButton = RobrixNeutralIconButton {grab_key_focus: false height: 42 margin: 0 padding: Inset{left: 12 right: 12} draw_text +: {color: #x333333 text_style: theme.font_regular{font_size: 12}} draw_bg +: {color: #xffffff color_hover: #xf2f5f3 color_down: #xe7f2e9 border_radius: 6}} mod.widgets.ArticlePrimary = mod.widgets.ArticleButton {width: Fill height: 46 align: Align{x: 0.5 y: 0.5} draw_bg +: {color: #x07c160 color_hover: #x06ad56 color_down: #x05984b} draw_text +: {color: #xffffff color_hover: #xffffff color_down: #xffffff}} mod.widgets.ArticleInput = TextInput {width: Fill height: 44 draw_cursor +: {color: #x07c160} draw_bg +: {color: #xffffff color_hover: #xffffff color_focus: #xffffff color_empty: #xffffff border_color: #xe5e5e5 border_color_focus: #x07c160} draw_text +: {color: #x191919 color_focus: #x191919 color_hover: #x191919 text_style: theme.font_regular{font_size: 14}}} mod.widgets.ArticleHtml = Html {selectable: true width: Fill height: Fit padding: 0 font_size: 14 font_color: #x191919 draw_text.color: #x191919 text_style_normal: theme.font_regular{font_size: 14} text_style_bold: theme.font_bold{font_size: 14} text_style_italic: theme.font_italic{font_size: 14} text_style_bold_italic: theme.font_bold_italic{font_size: 14} rmath := ArticleMath {} rdiagram := ArticleDiagram {} rimage := ArticleImage {} remoji := ArticleEmoji {} rcode := ArticleCode {} rcell := ArticleCell {}} @@ -152,7 +152,7 @@ script_mod! { width: Fill height: Fill flow: Down draw_bg.color: #xffffff padding: Inset{top: mod.widgets.SAFE_INSET_PAD_TOP + #(TOP) bottom: mod.widgets.SAFE_INSET_PAD_BOTTOM} header := SolidView {width: Fill height: 52 flow: Right align: Align{y: 0.5} padding: Inset{left: 8 right: 12} spacing: 8 draw_bg.color: #xededed - article_back := RobrixNeutralIconButton {width: 36 height: 44 padding: 12 spacing: 0 draw_bg +: {color: #x00000000 color_hover: #x00000000 color_down: #x00000000 border_size: 0} draw_icon +: {svg: ICON_CHEVRON_LEFT color: #x191919} icon_walk: Walk{width: 8 height: 14}} + article_back := RobrixNeutralIconButton {width: 36 height: 44 margin: 0 padding: 12 spacing: 0 draw_bg +: {color: #x00000000 color_hover: #x00000000 color_down: #x00000000 border_size: 0} draw_icon +: {svg: ICON_CHEVRON_LEFT color: #x191919} icon_walk: Walk{width: 8 height: 14}} article_heading := mod.widgets.ArticleLabel {width: Fit max_lines: 1 draw_text.text_style: theme.font_bold{font_size: 16}} header_fill := View {width: Fill height: Fill} // The writing view's article title, centred in the header as in the atlas. From c85e6b4b0056d8cb2cedbc8269b952786c61e4c7 Mon Sep 17 00:00:00 2001 From: ymote <151983+ymote@users.noreply.github.com> Date: Sat, 26 Sep 2026 14:57:40 -0700 Subject: [PATCH 05/10] Expose hosted Rinx resources to the Makepad app packager --- build.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/build.rs b/build.rs index d981078d..5d8ba5f9 100644 --- a/build.rs +++ b/build.rs @@ -1,4 +1,15 @@ fn main() { + // cargo-makepad discovers resources of Git/registry dependencies through + // a package-name.path file beside the compiled libraries. Rinx is also a + // hosted dependency, so publish its resource root like makepad-widgets. + let out_dir = std::path::PathBuf::from(std::env::var_os("OUT_DIR").unwrap()); + let profile_dir = out_dir.ancestors().nth(3).unwrap(); + std::fs::write( + profile_dir.join("rinx.path"), + std::env::var("CARGO_MANIFEST_DIR").unwrap(), + ) + .expect("write Rinx resource path for cargo-makepad"); + // Detect `cargo packager` builds using the `CARGO_PACKAGER_FORMAT` env var. println!("cargo::rustc-check-cfg=cfg(packaging_build)"); println!("cargo:rerun-if-env-changed=CARGO_PACKAGER_FORMAT"); From 1f1a6cf5ee193edc352bc12b9bedb9ec8059131e Mon Sep 17 00:00:00 2001 From: ymote <151983+ymote@users.noreply.github.com> Date: Sat, 26 Sep 2026 20:08:58 -0700 Subject: [PATCH 06/10] Host-owned Octos app peers and Rinx deployment modes (ADR 0007) Rinx no longer discovers AppCard's published connection. It consumes the scoped assistant service of octosense-app-peers (OctoSense-System-Apps crates/app-peers) in three deployments: - Hosted: the OctoSense shell offers a service when it creates the Rinx module; RinxModule::create claims it for its instance. No fallback kernel, no AI credentials, no AppCard; without an offer Rinx has no assistant. The module declares the four exact octos.* services. - Standalone local: Rinx owns one runtime, the packaged octos beside the executable (never PATH), under its own data root. It starts on the first authorized request and stops on exit (only that runtime). - Standalone remote: an explicit server authenticated by its token (kept in memory only); the server provisions the workspace and keeps running. Every mini-app instance gets its own kernel request context of Rinx's peer (separate transcript, workspace and memory namespace; octos UPCR-2026-034). Admission and dispatch use exact service names, account changes revoke, hosted close releases, and stale replies are dropped. The octos-local and octos-remote features keep the runtime out of octosense-module builds. Adds ADR 0007 with its implementation record, and process-level tests against a real kernel and a real authenticated octos serve with scripted models (tests/standalone_{local,remote}.rs, gated on RINX_TEST_OCTOS_BIN). App Hub moves to 46d67e51, which publishes the service names. Co-Authored-By: Claude Opus 5.5 (1M context) --- Cargo.lock | 184 ++++---- Cargo.toml | 15 +- docs/adr/0007-host-owned-octos-app-peers.md | 489 ++++++++++++++++++++ docs/adr/README.md | 1 + examples/miniapps/README.md | 8 +- src/app.rs | 4 + src/lib.rs | 1 + src/module.rs | 19 +- src/octos_service.rs | 422 +++++++++++++++++ src/octoscript_apps/mod.rs | 5 +- src/octoscript_apps/octos.rs | 485 +++++-------------- src/octoscript_apps/ui.rs | 151 +++--- tests/fixtures/mock_llm.py | 71 +++ tests/standalone_local.rs | 129 ++++++ tests/standalone_remote.rs | 154 ++++++ 15 files changed, 1612 insertions(+), 526 deletions(-) create mode 100644 docs/adr/0007-host-owned-octos-app-peers.md create mode 100644 src/octos_service.rs create mode 100644 tests/fixtures/mock_llm.py create mode 100644 tests/standalone_local.rs create mode 100644 tests/standalone_remote.rs diff --git a/Cargo.lock b/Cargo.lock index 64b68c96..1cb0ca07 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -173,23 +173,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "android_log-sys" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84521a3cf562bc62942e294181d9eef17eb38ceb8c68677bc49f144e4c3d4f8d" - -[[package]] -name = "android_logger" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05b07e8e73d720a1f2e4b6014766e6039fd2e96a4fa44e2a78d0e1fa2ff49826" -dependencies = [ - "android_log-sys", - "env_filter 0.1.4", - "log", -] - [[package]] name = "android_system_properties" version = "0.1.5" @@ -948,7 +931,7 @@ dependencies = [ "quote", "regex", "rustc-hash 2.1.1", - "shlex", + "shlex 1.3.0", "syn 2.0.119", ] @@ -1360,7 +1343,7 @@ dependencies = [ "find-msvc-tools", "jobserver", "libc", - "shlex", + "shlex 1.3.0", ] [[package]] @@ -1638,6 +1621,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "037e2a1a92236d0aff7e845093f64661d6df4c02c9fcc61a60e9e1d736fa392f" dependencies = [ "clap", + "clap_lex", + "is_executable", + "shlex 2.0.1", ] [[package]] @@ -2835,16 +2821,6 @@ dependencies = [ "syn 2.0.119", ] -[[package]] -name = "env_filter" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bf3c259d255ca70051b30e2e95b5446cdb8949ac4cd22c0d7fd634d89f568e2" -dependencies = [ - "log", - "regex", -] - [[package]] name = "env_filter" version = "2.0.0" @@ -2869,7 +2845,7 @@ checksum = "de671bd27a75a797dc9ae289ba1e77276e75e2026408aab65185384e2d5cd3f6" dependencies = [ "anstream", "anstyle", - "env_filter 2.0.0", + "env_filter", "jiff", "log", ] @@ -5235,6 +5211,15 @@ dependencies = [ "once_cell 1.21.4", ] +[[package]] +name = "is_executable" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82cb6a9f675da968c63b6208c641b9dca58fc0133ae53375736b1767b0cab8bd" +dependencies = [ + "windows-sys 0.59.0", +] + [[package]] name = "is_terminal_polyfill" version = "1.70.1" @@ -7480,8 +7465,8 @@ dependencies = [ [[package]] name = "octos-agent" -version = "2.0.3-rc.12" -source = "git+https://github.com/octos-org/octos.git?rev=18fcd3f16e527d2b601d7ae244f056fb711bb6b8#18fcd3f16e527d2b601d7ae244f056fb711bb6b8" +version = "2.0.3-rc.13" +source = "git+https://github.com/octos-org/octos.git?rev=6ad76e5c1e659bdf10ec05ae869428b48edccf7f#6ad76e5c1e659bdf10ec05ae869428b48edccf7f" dependencies = [ "async-trait", "base64 0.22.1", @@ -7520,7 +7505,7 @@ dependencies = [ "serde", "serde_json", "sha2 0.10.9", - "shlex", + "shlex 1.3.0", "similar", "tar", "tempfile", @@ -7539,31 +7524,10 @@ dependencies = [ "which 7.0.3", ] -[[package]] -name = "octos-app-transport" -version = "0.1.0" -source = "git+https://github.com/OctoSense-org/OctoSense-System-Apps.git?rev=1576bec6a585758e48c3252030cad2a9bf9c80db#1576bec6a585758e48c3252030cad2a9bf9c80db" -dependencies = [ - "android_logger", - "chrono", - "futures-util", - "log", - "octos-cli", - "octos-core", - "reqwest 0.12.28", - "serde", - "serde_json", - "tokio", - "tokio-tungstenite 0.24.0", - "tracing-subscriber", - "url", - "uuid", -] - [[package]] name = "octos-bus" -version = "2.0.3-rc.12" -source = "git+https://github.com/octos-org/octos.git?rev=18fcd3f16e527d2b601d7ae244f056fb711bb6b8#18fcd3f16e527d2b601d7ae244f056fb711bb6b8" +version = "2.0.3-rc.13" +source = "git+https://github.com/octos-org/octos.git?rev=6ad76e5c1e659bdf10ec05ae869428b48edccf7f#6ad76e5c1e659bdf10ec05ae869428b48edccf7f" dependencies = [ "aes 0.8.4", "async-trait", @@ -7591,8 +7555,8 @@ dependencies = [ [[package]] name = "octos-cli" -version = "2.0.3-rc.12" -source = "git+https://github.com/octos-org/octos.git?rev=18fcd3f16e527d2b601d7ae244f056fb711bb6b8#18fcd3f16e527d2b601d7ae244f056fb711bb6b8" +version = "2.0.3-rc.13" +source = "git+https://github.com/octos-org/octos.git?rev=6ad76e5c1e659bdf10ec05ae869428b48edccf7f#6ad76e5c1e659bdf10ec05ae869428b48edccf7f" dependencies = [ "agent-client-protocol", "argon2", @@ -7671,8 +7635,8 @@ dependencies = [ [[package]] name = "octos-core" -version = "2.0.3-rc.12" -source = "git+https://github.com/octos-org/octos.git?rev=18fcd3f16e527d2b601d7ae244f056fb711bb6b8#18fcd3f16e527d2b601d7ae244f056fb711bb6b8" +version = "2.0.3-rc.13" +source = "git+https://github.com/octos-org/octos.git?rev=6ad76e5c1e659bdf10ec05ae869428b48edccf7f#6ad76e5c1e659bdf10ec05ae869428b48edccf7f" dependencies = [ "chrono", "eyre", @@ -7685,8 +7649,8 @@ dependencies = [ [[package]] name = "octos-diagnostics" -version = "2.0.3-rc.12" -source = "git+https://github.com/octos-org/octos.git?rev=18fcd3f16e527d2b601d7ae244f056fb711bb6b8#18fcd3f16e527d2b601d7ae244f056fb711bb6b8" +version = "2.0.3-rc.13" +source = "git+https://github.com/octos-org/octos.git?rev=6ad76e5c1e659bdf10ec05ae869428b48edccf7f#6ad76e5c1e659bdf10ec05ae869428b48edccf7f" dependencies = [ "eyre", "octos-core", @@ -7697,8 +7661,8 @@ dependencies = [ [[package]] name = "octos-fleet" -version = "2.0.3-rc.12" -source = "git+https://github.com/octos-org/octos.git?rev=18fcd3f16e527d2b601d7ae244f056fb711bb6b8#18fcd3f16e527d2b601d7ae244f056fb711bb6b8" +version = "2.0.3-rc.13" +source = "git+https://github.com/octos-org/octos.git?rev=6ad76e5c1e659bdf10ec05ae869428b48edccf7f#6ad76e5c1e659bdf10ec05ae869428b48edccf7f" dependencies = [ "eyre", "octos-core", @@ -7713,8 +7677,8 @@ dependencies = [ [[package]] name = "octos-fleet-worker" -version = "2.0.3-rc.12" -source = "git+https://github.com/octos-org/octos.git?rev=18fcd3f16e527d2b601d7ae244f056fb711bb6b8#18fcd3f16e527d2b601d7ae244f056fb711bb6b8" +version = "2.0.3-rc.13" +source = "git+https://github.com/octos-org/octos.git?rev=6ad76e5c1e659bdf10ec05ae869428b48edccf7f#6ad76e5c1e659bdf10ec05ae869428b48edccf7f" dependencies = [ "async-trait", "eyre", @@ -7730,8 +7694,8 @@ dependencies = [ [[package]] name = "octos-llm" -version = "2.0.3-rc.12" -source = "git+https://github.com/octos-org/octos.git?rev=18fcd3f16e527d2b601d7ae244f056fb711bb6b8#18fcd3f16e527d2b601d7ae244f056fb711bb6b8" +version = "2.0.3-rc.13" +source = "git+https://github.com/octos-org/octos.git?rev=6ad76e5c1e659bdf10ec05ae869428b48edccf7f#6ad76e5c1e659bdf10ec05ae869428b48edccf7f" dependencies = [ "async-trait", "base64 0.22.1", @@ -7754,8 +7718,8 @@ dependencies = [ [[package]] name = "octos-memory" -version = "2.0.3-rc.12" -source = "git+https://github.com/octos-org/octos.git?rev=18fcd3f16e527d2b601d7ae244f056fb711bb6b8#18fcd3f16e527d2b601d7ae244f056fb711bb6b8" +version = "2.0.3-rc.13" +source = "git+https://github.com/octos-org/octos.git?rev=6ad76e5c1e659bdf10ec05ae869428b48edccf7f#6ad76e5c1e659bdf10ec05ae869428b48edccf7f" dependencies = [ "bincode", "chrono", @@ -7773,8 +7737,8 @@ dependencies = [ [[package]] name = "octos-pipeline" -version = "2.0.3-rc.12" -source = "git+https://github.com/octos-org/octos.git?rev=18fcd3f16e527d2b601d7ae244f056fb711bb6b8#18fcd3f16e527d2b601d7ae244f056fb711bb6b8" +version = "2.0.3-rc.13" +source = "git+https://github.com/octos-org/octos.git?rev=6ad76e5c1e659bdf10ec05ae869428b48edccf7f#6ad76e5c1e659bdf10ec05ae869428b48edccf7f" dependencies = [ "async-trait", "chrono", @@ -7795,8 +7759,8 @@ dependencies = [ [[package]] name = "octos-plugin" -version = "2.0.3-rc.12" -source = "git+https://github.com/octos-org/octos.git?rev=18fcd3f16e527d2b601d7ae244f056fb711bb6b8#18fcd3f16e527d2b601d7ae244f056fb711bb6b8" +version = "2.0.3-rc.13" +source = "git+https://github.com/octos-org/octos.git?rev=6ad76e5c1e659bdf10ec05ae869428b48edccf7f#6ad76e5c1e659bdf10ec05ae869428b48edccf7f" dependencies = [ "eyre", "metrics", @@ -7810,7 +7774,7 @@ dependencies = [ [[package]] name = "octos-sandbox" version = "0.1.0" -source = "git+https://github.com/octos-org/octos.git?rev=18fcd3f16e527d2b601d7ae244f056fb711bb6b8#18fcd3f16e527d2b601d7ae244f056fb711bb6b8" +source = "git+https://github.com/octos-org/octos.git?rev=6ad76e5c1e659bdf10ec05ae869428b48edccf7f#6ad76e5c1e659bdf10ec05ae869428b48edccf7f" dependencies = [ "clap", "eyre", @@ -7824,8 +7788,8 @@ dependencies = [ [[package]] name = "octos-services" -version = "2.0.3-rc.12" -source = "git+https://github.com/octos-org/octos.git?rev=18fcd3f16e527d2b601d7ae244f056fb711bb6b8#18fcd3f16e527d2b601d7ae244f056fb711bb6b8" +version = "2.0.3-rc.13" +source = "git+https://github.com/octos-org/octos.git?rev=6ad76e5c1e659bdf10ec05ae869428b48edccf7f#6ad76e5c1e659bdf10ec05ae869428b48edccf7f" dependencies = [ "chrono", "dirs", @@ -7845,8 +7809,8 @@ dependencies = [ [[package]] name = "octos-store" -version = "2.0.3-rc.12" -source = "git+https://github.com/octos-org/octos.git?rev=18fcd3f16e527d2b601d7ae244f056fb711bb6b8#18fcd3f16e527d2b601d7ae244f056fb711bb6b8" +version = "2.0.3-rc.13" +source = "git+https://github.com/octos-org/octos.git?rev=6ad76e5c1e659bdf10ec05ae869428b48edccf7f#6ad76e5c1e659bdf10ec05ae869428b48edccf7f" dependencies = [ "base64 0.22.1", "chrono", @@ -7865,8 +7829,8 @@ dependencies = [ [[package]] name = "octos-swarm" -version = "2.0.3-rc.12" -source = "git+https://github.com/octos-org/octos.git?rev=18fcd3f16e527d2b601d7ae244f056fb711bb6b8#18fcd3f16e527d2b601d7ae244f056fb711bb6b8" +version = "2.0.3-rc.13" +source = "git+https://github.com/octos-org/octos.git?rev=6ad76e5c1e659bdf10ec05ae869428b48edccf7f#6ad76e5c1e659bdf10ec05ae869428b48edccf7f" dependencies = [ "async-trait", "chrono", @@ -7884,8 +7848,8 @@ dependencies = [ [[package]] name = "octos-workflows" -version = "2.0.3-rc.12" -source = "git+https://github.com/octos-org/octos.git?rev=18fcd3f16e527d2b601d7ae244f056fb711bb6b8#18fcd3f16e527d2b601d7ae244f056fb711bb6b8" +version = "2.0.3-rc.13" +source = "git+https://github.com/octos-org/octos.git?rev=6ad76e5c1e659bdf10ec05ae869428b48edccf7f#6ad76e5c1e659bdf10ec05ae869428b48edccf7f" dependencies = [ "chrono", "eyre", @@ -7941,10 +7905,25 @@ dependencies = [ "serde_json", ] +[[package]] +name = "octosense-app-peers" +version = "0.1.0" +source = "git+https://github.com/OctoSense-org/OctoSense-System-Apps.git?rev=64aa865e306a1411a3f020903ddb7ac922aa30ae#64aa865e306a1411a3f020903ddb7ac922aa30ae" +dependencies = [ + "futures-util", + "log", + "octosense-octos-core", + "serde_json", + "tokio", + "tokio-tungstenite 0.24.0", + "url", + "uuid", +] + [[package]] name = "octosense-app-policy" version = "0.1.0" -source = "git+https://github.com/OctoSense-org/OctoSense-App-Hub.git?rev=b0591e2caa0dc5c62927f7b85dbf826a50618a03#b0591e2caa0dc5c62927f7b85dbf826a50618a03" +source = "git+https://github.com/OctoSense-org/OctoSense-App-Hub.git?rev=46d67e51b62827a1224b1aacddc2a7b9e69185fc#46d67e51b62827a1224b1aacddc2a7b9e69185fc" dependencies = [ "blake3", "makepad-widgets", @@ -7952,6 +7931,35 @@ dependencies = [ "serde_json", ] +[[package]] +name = "octosense-llm-config" +version = "0.1.0" +source = "git+https://github.com/OctoSense-org/OctoSense-System-Apps.git?rev=64aa865e306a1411a3f020903ddb7ac922aa30ae#64aa865e306a1411a3f020903ddb7ac922aa30ae" +dependencies = [ + "argon2", + "chacha20poly1305 0.10.1", + "chrono", + "flate2", + "qrcode", + "serde", + "serde_json", + "thiserror 2.0.20", + "url", +] + +[[package]] +name = "octosense-octos-core" +version = "0.1.0" +source = "git+https://github.com/OctoSense-org/OctoSense-System-Apps.git?rev=64aa865e306a1411a3f020903ddb7ac922aa30ae#64aa865e306a1411a3f020903ddb7ac922aa30ae" +dependencies = [ + "log", + "octos-cli", + "octosense-llm-config", + "serde_json", + "tokio", + "tracing-subscriber", +] + [[package]] name = "ohos-sys" version = "0.2.2" @@ -9307,10 +9315,10 @@ dependencies = [ "mime", "mime_guess", "num_cpus", - "octos-app-transport", "octoscript-makepad", "octoscript-ui-l0", "octoscript-widgets", + "octosense-app-peers", "octosense-app-policy", "percent-encoding", "pulldown-cmark 0.13.0", @@ -10535,6 +10543,12 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "shlex" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" + [[package]] name = "signal-hook-registry" version = "1.4.6" diff --git a/Cargo.toml b/Cargo.toml index b0f100a2..a9d75847 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,11 +17,14 @@ metadata.makepad-auto-version = "zqpv-Yj-K7WNVK2I8h5Okhho46Q=" article-core = { path = "crates/article-core", features = ["l0"] } rinx-miniapp-core = { path = "crates/miniapp-core" } uuid = { version = "1", features = ["v4"] } -octos-app-transport = { git = "https://github.com/OctoSense-org/OctoSense-System-Apps.git", rev = "1576bec6a585758e48c3252030cad2a9bf9c80db" } +## The assistant (ADR 0007): the scoped service contract a host injects. The +## local-runtime and remote connectors are optional (`octos-local`, +## `octos-remote`), so a hosted build links no runtime of its own. +octosense-app-peers = { git = "https://github.com/OctoSense-org/OctoSense-System-Apps.git", rev = "64aa865e306a1411a3f020903ddb7ac922aa30ae" } octoscript-ui-l0 = { git = "https://github.com/OctoSense-org/Octoscript.git", rev = "68f6a9df55692b5d8ef8873a12721e279a3f40d6" } octoscript-makepad = { git = "https://github.com/OctoSense-org/Octoscript-Makepad.git", rev = "b9034566b0607c5bb8c04134d17139f99989e1d0" } octoscript-widgets = { git = "https://github.com/OctoSense-org/Octoscript-Makepad.git", rev = "b9034566b0607c5bb8c04134d17139f99989e1d0" } -octosense-app-policy = { git = "https://github.com/OctoSense-org/OctoSense-App-Hub.git", rev = "b0591e2caa0dc5c62927f7b85dbf826a50618a03", features = ["splash"] } +octosense-app-policy = { git = "https://github.com/OctoSense-org/OctoSense-App-Hub.git", rev = "46d67e51b62827a1224b1aacddc2a7b9e69185fc", features = ["splash"] } article-makepad = { path = "crates/article-makepad" } ## The OctoSense module contract. Only a host build uses it, and the host redirects ## all of makepad to its own copy (OctoSense-org/makepad rinx/octosense-module-windows). @@ -157,7 +160,13 @@ dispatch2 = "0.3" default = ["standalone"] ## The standalone app's entry point (window, menus, `app_main!`). A host that ## links Rinx as a module disables it. -standalone = [] +standalone = ["octos-local", "octos-remote"] +## Standalone Octos modes (ADR 0007). `octos-local`: Rinx owns one local +## kernel (the packaged `octos` next to the executable, never one on PATH), +## started on the first authorized AI request and stopped on exit. +## `octos-remote`: an explicitly configured remote octos server. +octos-local = ["octosense-app-peers/octos-core"] +octos-remote = ["octosense-app-peers/ws"] ## Rinx as an OctoSense app module (`rinx::module::RINX_MODULE`). octosense-module = ["dep:makepad-app-module"] ## Experimental CPU HTML/CSS article preview; the native editor stays available. diff --git a/docs/adr/0007-host-owned-octos-app-peers.md b/docs/adr/0007-host-owned-octos-app-peers.md new file mode 100644 index 00000000..f0355114 --- /dev/null +++ b/docs/adr/0007-host-owned-octos-app-peers.md @@ -0,0 +1,489 @@ +# ADR 0007: Host-owned Octos app peers and Rinx deployment modes + +- Date: 2026-09-26 +- Status: Accepted; implemented in part (see the implementation record). Hosted + ROM Home on the OnePlus 6 and the native hosted desktop flow remain unverified. +- Extends [ADR 0005](0005-octoscript-miniapps-matrix-octos.md) and + [ADR 0006](0006-shared-app-hub-miniapps.md). Proposes replacing AppCard-dependent + connection discovery and mini-app-owned agent allocation, while retaining the + shared package format, Matrix contracts and instance grants. + +## Context + +Rinx runs as a standalone application or a native module in OctoSense desktop +and ROM Home. It also hosts Octoscript mini apps. These are different ownership +boundaries: an OctoSense app can have an app agent, while a mini app inside Rinx +uses services granted by Rinx. A mini app does not need its own Octos kernel, +provider configuration or autonomous peer. + +OctoSense should know that an app needs Octos from its native API capability +declaration. When launching an authorized app, the host should create or resume +an app peer owned by the system agent. The system agent and app peer must be able +to exchange input, questions, answers and results throughout the app's lifetime. +Opening an app must not require an LLM to decide whether to establish this link. + +The intended deployment uses one Octos kernel and one shared provider profile +per OctoSense user runtime. Apps do not choose independent providers or supply +provider credentials. Selecting a model configured by the system does not require +a separate profile. Separate conversation state and app data remain necessary. + +## Decision + +### 1. Capabilities determine access; the host owns the peer + +Use the same capability vocabulary for native module descriptors and App Hub +manifests. The existing Rinx integration recognizes these service names: + +```json +{ + "capabilities": [ + "octos.session.open", + "octos.session.history", + "octos.turn.start", + "octos.turn.interrupt" + ] +} +``` + +This is an example subset of a manifest, not a complete package. Each app requests +only what it uses. Admission checks exact registered names; a string beginning +with `octos.` does not automatically grant access. Native linkage to Octos also +does not grant authority. The host intersects declarations with supported APIs, +host policy and user grants, and checks the resulting lease on every request. + +At launch, an app with granted Octos access receives a scoped host service handle. +For an app authorized to run an agent, the host creates or resumes its peer on +behalf of the system agent, recording that system session as the originator. +History-only access must not implicitly grant turn execution. Creating a peer +does not itself require a model inference or a background task. + +Apps without Octos access do not allocate peers. If an app's AI feature is +optional, its ordinary UI remains usable without a provider. Unsupported required +capabilities make an app unavailable with an explicit reason. This ADR does not +invent an optional-capabilities field in the current manifest schema; any such +schema extension must be agreed with App Hub. + +### 2. One system kernel, one app peer, shared provider configuration + +```mermaid +flowchart TD + Host[OctoSense host and capability broker] --> Kernel[Shared Octos kernel] + Kernel --> Root[System agent] + Root <-->|input, questions, answers, results| Rinx[Rinx app peer] + Root <-->|input, questions, answers, results| Other[Other app peer] + Mini[Rinx mini apps] --> Grants[Rinx Matrix and Octos service boundary] + Grants --> Rinx + Grants --> Matrix[Rinx Matrix SDK] +``` + +The host persists an association between the OctoSense user, app identity, +relevant account scope, peer session, system originator and app workspace. +Reopening an app resumes the intended peer instead of creating an unrelated peer +on every UI mount. A change of Matrix account must not expose a previous account's +history, memory or pending replies. Peer identity and workspace paths come from +the host, never from an app request. + +The system agent can send follow-up input, receive progress and results, answer +ordinary peer questions, and interrupt its app peers. App peers can request help +and return information to the system agent. This is an interactive relationship, +not just a single task followed by a final result. Human approvals retain their +existing policy: the system agent's ability to answer a question is not blanket +authority to approve a tool or grant another app's data. + +Peers remain directly owned by the system agent. Rinx does not need to spawn +further peers for its mini apps. The current one-level peer delegation rule is +compatible with this topology. Host routing must support launching Rinx without +first opening AppCard or a system-agent chat window. + +### 3. Model selection stays under host control + +The shared profile owns the provider configuration and credentials. The system +agent or host policy can select an allowed configured model for an app peer. +Apps cannot create provider configurations, change the system default or submit +credentials through the mini-app API. + +Octos already supports `peer_handoff` with an optional `model` key naming a +configured `sub_provider`, such as `strong`. The peer stays in the master's +profile. The platform can restrict those configured choices to its selected +provider; the underlying kernel's ability to configure other providers does not +require exposing that choice to apps. + +There is a protocol gap to review: the inspected raw OUP `peer/prepare` request +does not accept this model field. OUP `profile/sub_providers/*` manages configured +choices, and `profile/llm/select` changes the profile default; neither is a +verified API for assigning a different model to one existing peer. The host path +needs parity with peer creation through `peer_handoff`, and an explicit contract +for changing an existing peer's model if required. Apply changes between turns +and expose the effective model or fallback. Do not implement this by editing +peer files from Rinx or changing the global default for a single app. + +### 4. App data and conversation isolation do not require app providers + +Each app has its own workspace, conversation state, scoped tools and limits. +Per-app storage lives under a host-owned app namespace. For Rinx, Matrix account +identity also scopes private data. A future move to separate app processes must +preserve these logical identities and the same service contract. + +In current Octos code, a `ProfileRuntime` owns memory, recall and policy as well +as the LLM provider. Therefore sharing a provider profile and giving peers +different working directories does not by itself isolate long-term memory. +The proposed shared-profile design requires app/account namespaces on memory +capture, recall, retrieval and automatic prompt injection. Explicitly shared +system knowledge can be separate from private app memory. The system agent can +obtain app information through authorized peer interactions; app histories must +not automatically become input to every other app. + +App isolation is a host/kernel enforcement requirement, not a prompt instruction. +Raw OUP is not handed to untrusted apps: current peer originator checks operate +inside one user's trust domain and do not replace app capability leases. The +broker must bind requests and replies to their app, account and lease generation. +In-process native modules remain trusted code; Splash isolation is not OS process +isolation for arbitrary native Rust. + +### 5. Rinx mini apps use Rinx's services + +Mini apps keep the package, instance, Matrix account, optional room, storage and +capability boundaries from ADRs 0005 and 0006. They receive neither a kernel nor +an autonomous persistent peer. Rinx mediates their Octos requests through its app +service and the host-managed Rinx agent arrangement. + +Mini apps may have separate request or conversation state to prevent one app's +prompts and replies from appearing in another. Such state is not an independent +agent or provider profile. The Octos integration review must choose how to enforce +those request contexts; simply forwarding every mini app into one unrestricted +Rinx transcript is insufficient. Existing ordinary mini-app sessions can remain +as a transitional adapter until equivalent isolation is demonstrated. + +A mini app's request must not inherit all of Rinx's Matrix privileges. Reading +room data for AI requires the applicable Matrix read grant and Octos grant. +Posting, editing, deleting and other Matrix actions continue through Rinx's +authorized SDK adapters. A model output cannot expand a mini app's permissions. + +## Rinx deployment models + +| Concern | Standalone Rinx, desktop or mobile | Rinx inside OctoSense desktop or ROM Home | +| --- | --- | --- | +| UI entry | Rinx owns its window/activity and navigation | Native Rinx module uses the shell's viewport, windows and navigation | +| Current build boundary | Default `standalone` feature | `--no-default-features --features octosense-module`; `rinx::module::RINX_MODULE` | +| Octos ownership | Rinx owns an optional local runtime, or explicitly connects to a configured external provider | OctoSense owns the shared runtime; Rinx receives a scoped service handle | +| Agent role | Rinx's agent is the application root; no OctoSense system agent is assumed | Rinx's agent is a peer owned by the OctoSense system agent | +| Provider settings | Rinx-owned settings for a local runtime, or the external service's settings | Shared OctoSense settings; no duplicate provider setup in Rinx | +| Kernel version | Pinned with the standalone distribution when bundled locally | Pinned by OctoSense; Rinx must be compatible with the host API | +| Private state | Rinx-owned data root with account/app namespaces | Host-provided Rinx namespace, further scoped by account/app | +| Mini apps | Same App Hub packages and Matrix/Octos service contracts | Same App Hub packages and Matrix/Octos service contracts | +| Shutdown | Stop a Rinx-owned local runtime; disconnect without stopping an external runtime | Release Rinx leases; leave the shared kernel and other apps running | + +### Deployment selection and packaging + +There are two application deployments and three Octos connection modes: + +| Application deployment | Octos mode | Selected by | Runtime owner | +| --- | --- | --- | --- | +| Standalone Rinx | Local | Rinx's AI settings | Rinx | +| Standalone Rinx | Remote | Explicit server configuration in Rinx | External Octos service | +| OctoSense native module | Hosted | Module creation by the OctoSense shell | OctoSense | + +Hosted mode comes from the native host context, not an editable mini-app field, +environment guess, installed AppCard detection or a failed connection attempt. +Hosted Rinx cannot switch to local or remote ownership from its own settings. +Standalone mode must not silently attach to an unrelated process's provider. +An unconfigured or disabled provider is a normal state in either deployment; +Matrix and the offline editor remain usable. + +Keep the existing `standalone` and `octosense-module` entry features. A standalone +desktop release builds Rinx's binary; a shell consumes the Rinx library with its +default features disabled. These existing commands describe the build boundary: + +```sh +# Standalone desktop executable, using the default standalone feature. +cargo build --release --locked --bin rinx + +# Library integration check; this does not build an OctoSense shell or APK. +cargo check --locked --lib --no-default-features --features octosense-module +``` + +Standalone Android packaging produces Rinx's own application. Hosted Android +packaging belongs to OctoSense ROM Home and links the module into that host. +Installing a Home test APK is not a ROM flash or a standalone Rinx release. +Desktop and ROM host releases choose their native runtime locks; the standalone +release chooses its own compatible pins. All modules linked into one host must +resolve a single compatible Makepad/Octoscript runtime and service interface. + +The local kernel packaging dependency must be optional and separate from the +client/provider interface. A standard standalone package offering local AI ships +one pinned compatible kernel. A hosted Rinx library must not pull that owned +runtime into the shell's build. Cargo feature unification must be checked at the +final host workspace, not inferred from Rinx's feature names alone. New feature +names and platform artifact paths will be chosen in implementation; none are +claimed to exist by the commands above. + +### Standalone with a local kernel + +Rinx owns a single local runtime for the application, its provider settings and +its private kernel data root. The local runtime can be embedded or an owned child +process according to platform packaging; both use the same OUP service adapter. +Opening another mini app must not create another kernel. The Rinx agent is the +root application agent, so this mode does not manufacture an OctoSense system +agent merely to recreate the hosted peer relationship. + +Start the runtime on the first authorized AI operation, or an explicit action in +AI settings. Establish the transport, negotiate supported services and prepare +the account-scoped workspace before enabling agent operations. Starting a +transport is not proof that a provider is authenticated or ready. Report startup +and provider errors in Rinx, with retry; ordinary Matrix use remains available. + +Persist non-secret mode/settings separately from protected credentials. Allocate +the kernel root and app workspaces under Rinx-owned storage, independently of an +OctoSense installation or another desktop Octos profile. Do not import that other +profile's provider keys, memories or Matrix credentials implicitly. If a child +process is used, launch the packaged executable directly and track ownership; +do not find a random executable on `PATH` or terminate processes by name. + +On shutdown or local-provider replacement, revoke dependent request leases, +cancel or finish owned work according to policy, disconnect and stop only the +runtime Rinx owns. The implementation must verify shutdown rather than assume +that dropping a UI reference terminates the kernel. + +### Standalone with a remote kernel + +Remote mode is an explicit alternative to local mode. Rinx stores the selected +endpoint, authenticated profile reference and protected transport credential. +The remote server owns model-provider credentials, model configuration and its +kernel lifetime. Rinx does not need an independently configured LLM provider in +addition to the server. Disconnecting or exiting Rinx must not stop the server. + +Negotiate the APIs required by the installed mini app and bind each operation to +the authenticated Rinx account/app context. The server must provide or validate +the corresponding remote workspace namespace. A path under Rinx's local data +directory is not a remote workspace, and a remote connection does not grant the +server access to that directory. If scoped workspace provisioning is unavailable, +disable the affected Octos operations with a reason instead of broadening access +or claiming that a connection alone makes the mini app runnable. + +Switching servers, profiles or accounts revokes old request authority and drops +late replies before the replacement provider is attached. Local app documents +remain local unless an authorized request explicitly transfers them. Reconnect +restores only the sessions belonging to the selected server and current account. + +### Hosted in OctoSense desktop or ROM Home + +The shell supplies a scoped Octos service provider when creating the native Rinx +module. The same service contract applies on desktop and mobile. Rinx registers +the required native capabilities so the shell can determine its Octos needs +before launch. The host creates/resumes the Rinx peer under the system agent and +supplies the peer binding together with its app namespace and effective grants. + +The hosted module must not initialize a fallback kernel, maintain independent AI +credentials, or require AppCard to publish a connection first. Kernel startup, +model selection and provider configuration belong to OctoSense. Rinx can display +provider availability and an entry to the host's AI settings, but does not offer +an independent endpoint/key form in hosted mode. Missing host services produce +an unavailable AI state without changing the deployment mode. + +Closing Rinx releases its leases and subscriptions. It does not retire the host +connection, stop the kernel, terminate another app's work or delete system AI +configuration. Logout also revokes Matrix-account-bound requests and prevents +their later restoration under another account. The shell owns any approved +background work and the persisted Rinx peer's lifecycle. + +### Provider contract and division of implementation + +Rinx should consume a provider interface, not the shell's process-global raw +connection. The following are contract requirements, not new OUP method names: + +| Contract surface | Rinx responsibility | Provider/host responsibility | +| --- | --- | --- | +| Availability and services | Render actual state; reject unsupported calls | Report readiness, negotiated services and replacement/revocation | +| Open an app request context | Supply host-authenticated account/app identity and granted lease | Bind the correct peer/request context and validated workspace | +| Requests and events | Enforce Matrix/mini-app grants; route replies to the originating instance | Enforce effective tools, memory scope and resource limits; correlate events | +| Model/settings presentation | Show effective model/status and the appropriate settings entry | Select configured model and retain provider secrets | +| Cancellation and release | Revoke leases on close/account change; discard stale replies | Cancel scoped work and release context without stopping unrelated work | +| Runtime shutdown | Invoke only for a Rinx-owned local provider | Distinguish owned local lifetime from borrowed hosted/remote lifetime | + +Rinx can implement deployment selection, local/remote ownership, provider +injection points, UI state, lease invalidation and tests within its repository. +OctoSense must supply the native injection and root-owned peer binding. Octos +must supply or confirm the remote workspace, peer/model, memory and request-scope +contracts identified above. Until those exist, an adapter must report the +missing capability; it must not substitute a privileged ordinary session and +claim the hosted design is complete. + +Preserve the existing account/app storage layout where possible. If a migration +is needed, make it explicit and recoverable. Standalone and hosted installations +must not concurrently open the same Matrix database, transfer login secrets or +merge kernel stores automatically. Deployment mode is a packaging/ownership +choice, not an automatic account migration mechanism. + +### Deployment completion criteria + +| Mode | Required evidence before marking implemented | +| --- | --- | +| Standalone local | Packaged runtime starts on an authorized request; two mini apps share it with isolated request state; restart restores intended state; Rinx exit stops only its owned runtime | +| Standalone remote | Real authenticated connection and scoped workspace work; profile/account replacement rejects stale replies; exit leaves the server running | +| Hosted desktop | Launch Rinx before AppCard; use the system provider/peer; exchange a question and answer with the system agent; closing Rinx leaves a second app's peer functional | +| Hosted ROM Home | Exercise the same service flow on OnePlus 6, including Back/background/resume and process restart; verify that no Rinx-owned kernel is started | + +These criteria complement the cross-repository acceptance list below. Build +checks alone establish neither runtime ownership nor live-service compatibility. +The deployment specification is complete for review; implementing these modes +and recording their evidence remains separate work. + +The initial hosted design can run in the OctoSense process. Moving app UIs to +separate processes later changes the broker transport, not kernel ownership. +Per-app kernel instances or independently versioned kernels inside that process +are not part of this decision. + +## Lifecycle and resource policy + +The host manages peer creation, restoration, input scheduling and termination. +Persist the system originator or explicitly rebind ownership through a supported +kernel operation after restart. An ordinary session with a convenient name is +not a substitute for a correctly registered peer. + +Closing a mini app revokes its lease, cancels its pending work where supported and +drops late replies. Closing Rinx releases foreground app resources; background +agent work requires an explicit host policy. Logout revokes account-bound work. +Reopening an authorized app can restore its saved state without keeping every +peer runtime resident while idle. + +Concurrent apps need bounded queues, fair scheduling, cancellation and per-app +token/tool limits under the host's total budget. Neither the runtime cache size +nor the per-turn peer-handoff limit is the maximum number of installed apps. +Concrete limits must follow desktop/mobile measurements and provider limits; +this ADR does not claim unlimited parallel turns. + +## Implementation evidence and gaps + +These were the source findings when the ADR was proposed; the implementation +record below says what changed: + +| Area | Inspected implementation | Required integration | +| --- | --- | --- | +| Native Rinx declaration | `src/module.rs` declares `net`, `storage`, `audio.output`, `clipboard`; no Octos capability | Add the agreed native capability declaration and host service injection | +| Native agent control | Rinx's `ServiceExecutor` currently returns unavailable | Define authorized app operations; peer messaging alone does not expose every UI/Matrix action | +| Mini-app capabilities | The pinned Hub policy and Rinx adapters know four `octos.*` services | Coordinate publication, host admission and supported service versions | +| Connection ownership | `KernelProvider::shared` discovers AppCard's published connection | Replace implicit discovery with the shell-owned provider/broker handle | +| Mini-app execution | Each current provider creates an ordinary `rinx-mini-*` session | Implement the app-peer arrangement while preserving request isolation | +| Peer primitives | Octos stages peers, records originators, routes input/questions and supports configured model selection | Bind launch/resume lifecycle to the system agent and host API | +| Memory | Current profile runtime shares memory and recall stores | Add app/account scoping before claiming isolated persistent memory | +| Standalone | Explicit remote connection UI and standalone entry exist | Complete local-runtime provisioning and verify remote workspace behavior | + +Relevant Rinx sources: [module](../../src/module.rs), +[Octos adapter](../../src/octoscript_apps/octos.rs), +[package admission](../../src/octoscript_apps/package.rs), +[mini-app UI](../../src/octoscript_apps/ui.rs), and +[build features](../../Cargo.toml). + +Octos source evidence is pinned to inspected revision +`6ad76e5c1e659bdf10ec05ae869428b48edccf7f`: +[peer tool model argument](https://github.com/octos-org/octos/blob/6ad76e5c1e659bdf10ec05ae869428b48edccf7f/crates/octos-agent/src/tools/peer_handoff.rs), +[peer ownership and delegation](https://github.com/octos-org/octos/blob/6ad76e5c1e659bdf10ec05ae869428b48edccf7f/crates/octos-cli/src/peers/mod.rs), +[OUP requests and model resolution](https://github.com/octos-org/octos/blob/6ad76e5c1e659bdf10ec05ae869428b48edccf7f/crates/octos-cli/src/api/ui_protocol_transport.rs), +and [profile-owned memory](https://github.com/octos-org/octos/blob/6ad76e5c1e659bdf10ec05ae869428b48edccf7f/crates/octos-cli/src/runtime/profile.rs). +The Rinx capability additions are in +[Hub policy revision b0591e2c](https://github.com/OctoSense-org/OctoSense-App-Hub/blob/b0591e2caa0dc5c62927f7b85dbf826a50618a03/crates/app-policy/src/manifest.rs). +Recheck each consumer's actual pin during implementation; these references are +evidence baselines, not an instruction to downgrade its dependencies. + +## Cross-repository review and acceptance + +OctoSense owns native capability discovery, broker injection, system-agent +identity, launch/resume and shared AI settings. Octos owns peer/OUP behavior, +memory namespaces and effective per-request tool authority. App Hub owns the +published capability/schema contract. Rinx owns its deployment adapters, Matrix +SDK authority, account scoping and nested mini-app lifecycle. + +Before implementation, the OctoSense/Octos review must resolve the host peer +creation/resume API, model selection parity, memory namespaces and isolated +mini-app request contexts. It must also agree how permission prompts reach the +user and what background work survives an app close. No new raw RPC method or +manifest field in this ADR should be treated as an already available API. + +Acceptance must cover: + +1. Native and Hub declarations select the correct host services; unsupported or + ungranted calls are denied, and non-AI apps allocate no peer. +2. Rinx and another app run concurrently using one kernel and shared AI settings, + without opening AppCard first. Both remain independently addressable. +3. The system agent sends input, receives a peer question, answers it, observes + continuation and interrupts work. Replies and approvals reach the right app. +4. Launch, close, restart and logout preserve ownership and revoke stale leases; + no old reply reaches a new account or instance. +5. Workspace, transcript, memory and tool tests demonstrate app/account isolation, + including automatic memory injection and simultaneous Rinx mini-app requests. +6. Selecting a configured model affects only the intended peer, keeps credentials + with the host and reports fallback; it does not change the profile default. +7. Standalone local and external-provider modes work without OctoSense. Hosted + Rinx cannot spawn a second kernel, and closing it leaves other peers usable. +8. Current macOS desktop and OnePlus 6 ROM Home builds exercise these flows; + record native evidence and exact revisions separately from headless tests. + +## Implementation record + +The decision is implemented across four repositories. Kernel contracts came +first, and each consumer builds on the published revision of the one before it. +The review questions were resolved with the conservative options below and are +listed for the owners' confirmation. + +| Layer | Repository and change | What it provides | +| --- | --- | --- | +| Kernel | octos-org/octos#2555, UPCR-2026-034 | `peer/prepare` with `model` (parity with `peer_handoff`, effective model and fallback reported), `memory_namespace` (host-owned app peer bound to its workspace and an app/account memory namespace, system originator persisted), `resume` and a kernel-provisioned workspace for remote hosts. Adds `peer/model/set` (one peer's lane between turns, profile default untouched), `peer/context/open|close` (bound request contexts: kernel-minted sessions, child namespaces, refusal after close) and memory isolation for capture, retrieval, prompt injection, episodes and the refresh sweep | +| Capability contract | OctoSense-App-Hub#14 (`9e986135`, on main from `46d67e51`) | The exact `octos.*` and `matrix.*` service names, admitted by exact name, with store wording; history does not grant turns | +| Broker | OctoSense-System-Apps#14, #15 (`crates/app-peers`, `64aa865e`) | The contract Rinx consumes (`OctosAppService`, `OctosContext`), creation-time injection (`offer` / `claim` / `withdraw`) and the broker used for all three deployments. The broker makes one system-owned peer per app and account and one kernel request context per mini-app instance, checks the lease on every request and before every reply, and refuses a kernel without UPCR-2026-034. It runs over the shell kernel, an owned local kernel or a token-authenticated remote server | +| Rinx | this change | `src/octos_service.rs` selects the deployment: hosted from module creation, standalone local or remote from Rinx's assistant settings. `src/module.rs` declares the four `octos.*` services and claims the injected service. Mini apps get request contexts (`src/octoscript_apps/octos.rs`); admission and dispatch use exact names. Account changes revoke; hosted close releases; standalone exit stops only an owned runtime. The `octos-local` / `octos-remote` features keep the runtime out of `octosense-module` builds | + +`KernelProvider::shared` and the AppCard connection discovery are gone. No mode +starts a fallback kernel or substitutes an ordinary privileged session. A hosted +Rinx without an injected service has no assistant. Its AI settings entry points +to OctoSense's Settings → Accounts → AI providers. + +### Decisions on the open review questions + +- **Permission prompts.** Tool approvals raised in a mini app's context go to + Rinx's native approval UI and are answered by the person. The system agent's + ability to answer a peer's question is never used to approve a tool. +- **Background work after close.** This is the conservative choice. Closing a + mini app closes its context and interrupts its turn. Closing Rinx releases its + contexts and interrupts its peer's running turn. The peer, its workspace and + its memory stay for the next launch, and the shared kernel keeps running. +- **Model selection.** Host policy may set a configured lane for an app's peer + (`BrokerConfig::model_lane`, `peer/model/set`). No app-facing API selects a + model or provider. +- **Remote credentials.** The standalone remote token stays in memory and is asked + for again after a restart. Only the URL and profile are persisted. The + connector authenticates by token only. + +### Acceptance evidence (2026-09-27) + +Kernel builds are octos#2555 (`cf2b4000`) in release. Models are standard-library +Python fixtures; no provider key or Matrix credential is used anywhere. + +| Criterion | Evidence | State | +| --- | --- | --- | +| 1. Declarations select services; ungranted calls denied; non-AI apps allocate no peer | App Hub admission tests (exact names, prefixes refused, history ≠ turn); app-peers `effective_services`, `apps_without_assistant_services_allocate_no_peer`, `history_access_does_not_allow_a_turn_and_ungranted_apps_get_no_context` (no kernel connection made); Rinx module declaration | Met (headless) | +| 2. Rinx and another app share one kernel and settings without AppCard, independently addressable | app-peers `two_apps_share_one_kernel_and_closing_one_leaves_the_other_usable` on a real kernel: one kernel generation, two connections, distinct peers owned by `_main:api:octosense#system` | Met (headless); native desktop pending the shell wiring | +| 3. System agent input, peer question, answer, continuation, interrupt | `the_system_agent_and_the_app_peer_exchange_a_question_and_answer` (`peer_send_input` → `ask_user_question` → kernel wake → `peer_respond` → "PEER GOT 42") and `closing_the_app_interrupts_its_peers_running_work` (`active` → `interrupted`), real kernel, scripted model | Met (headless, scripted model) | +| 4. Launch/close/restart/logout preserve ownership; no old reply reaches a new account or instance | Kernel: closed contexts refused at bootstrap and at every turn start. Broker: late-reply tests on the scripted and the real kernel (a slow turn during an account switch delivers nothing). Restart resumes the same peer (real kernel, and Rinx `standalone_local`) | Met (headless) | +| 5. Workspace, transcript, memory and tool isolation, incl. automatic injection and simultaneous mini-app requests | octos `should_isolate_app_peer_workspace_and_memory_from_the_system_and_each_other`, `should_open_isolated_request_contexts_and_refuse_them_after_close`, `should_never_extract_an_app_bound_session_into_the_profile_memory`; Rinx `standalone_local` (two contexts, one peer) | Met (kernel tests) | +| 6. Model selection affects only the intended peer, keeps credentials with the host, reports fallback, leaves the default | octos `should_select_a_configured_model_for_one_peer_without_touching_the_profile_default` (a context runs on its peer's lane) | Met (kernel tests) | +| 7. Standalone local and remote work without OctoSense; hosted cannot spawn a kernel; closing leaves others usable | Rinx `tests/standalone_local.rs` and `tests/standalone_remote.rs` below. `cargo tree` of `--no-default-features --features octosense-module` has no `octosense-octos-core`. app-peers release test | Met (process level); native UI pending | +| 8. macOS desktop and OnePlus 6 ROM Home native flows | — | **Unverified.** The phone is in use by someone else and was not touched | + +Deployment completion criteria: + +| Mode | Evidence | State | +| --- | --- | --- | +| Standalone local | `standalone_rinx_owns_one_local_runtime_and_stops_only_it`: no kernel before the first request; the packaged kernel (explicit path, never PATH) under Rinx's data root; two mini apps share it with separate contexts; exit stops Rinx's kernel and leaves another owner's; restart resumes the same peer | Met at process level | +| Standalone remote | `standalone_rinx_uses_an_explicit_authenticated_remote_server` against `octos serve --auth-token `: wrong token refused; turn in a server-provisioned workspace; the token never written to disk; an account change drops the late reply; exit leaves the server running | Met at process level | +| Hosted desktop | Broker and injection tested; shell wiring follows in the OctoSense-Desktop change | Pending | +| Hosted ROM Home | — | Unverified (no device access) | + +Rinx checks: `cargo test --locked --features agent_chat --lib` (218 passed), `cargo check --lib` +and `cargo check --lib --no-default-features --features octosense-module` without +new warnings. + +Known limits: the kernel queued a second `peer_send_input` to an already-used +peer without running it within two minutes in one scripted run. The exchange +itself is covered by the first-input test; a kernel follow-up is recorded. +Per-app token/tool budgets and fair scheduling beyond the kernel's existing +limits are not part of this change. diff --git a/docs/adr/README.md b/docs/adr/README.md index a2383168..e957ecc0 100644 --- a/docs/adr/README.md +++ b/docs/adr/README.md @@ -8,3 +8,4 @@ implemented. An ADR is not evidence that a feature has shipped. | [0001](0001-matrix-moments.md) | Accepted; first slice implemented | Matrix Moments, timeline audiences, and private self-chat/File Transfer | | [0002](0002-octoscript-mini-app-authority.md) | Proposed; source review complete | Octoscript mini-app containment, account delegation and Markdown/HTML editor | | [0003](0003-shared-article-components.md) | Accepted; implemented | Standalone article libraries, host authority and optional Blitz preview | +| [0007](0007-host-owned-octos-app-peers.md) | Accepted; implemented in part (native hosted flows unverified) | Host-owned Octos app peers and Rinx deployment modes | diff --git a/examples/miniapps/README.md b/examples/miniapps/README.md index f29136b2..8eeb413a 100644 --- a/examples/miniapps/README.md +++ b/examples/miniapps/README.md @@ -1,19 +1,19 @@ # Octoscript mini apps in Rinx -The `matrix-octos-script` example uses the current OctoSense `main.splash` bundle format and calls `host.request` directly. It reads a Matrix profile, opens and hydrates its own session on the shared core, and sends a model turn. +The `matrix-octos-script` example uses the current OctoSense `main.splash` bundle format and calls `host.request` directly. It reads a Matrix profile, opens and hydrates its own assistant conversation (a request context of Rinx's assistant peer), and sends a model turn. The `matrix-octos` example is an ordinary L0 bundle: `page.card`, `page.data.json`, a kit, the OctoSense `manifest.json`, and declarative `bindings.json`. Rinx uses the shared Octoscript checker/lowerer for L0 and the shared App Hub entry resolver for `main.splash`, with native Makepad Splash widgets for both. Service results are live; the example does not substitute fixtures for Matrix or Octos. ## Try it 1. Log in to Matrix in Rinx. On desktop, choose **Mini apps** in the sidebar. On mobile, choose **Discover → Mini apps**. -2. In OctoSense, open AppCard once to connect its Octos core. Rinx captures that same connection when a mini app starts. Standalone Rinx offers an explicit Octos URL/profile/token form. +2. In OctoSense, nothing to set up: the shell gives Rinx its assistant when it creates the Rinx module (ADR 0007), and the AI provider is chosen in OctoSense's Settings → Accounts → AI providers. AppCard is not involved. Standalone Rinx chooses in the assistant settings of this screen: **Use this device** (Rinx's own local runtime, the packaged `octos` beside the executable, with a provider you enter) or an explicit Octos server URL/profile/token (the token is kept in memory only). 3. Enter the full path of the `matrix-octos-script` or `matrix-octos` folder, choose **Review bundle**, and review its declared services. Leave the room empty for this example. 4. Choose **Run**, then **Read my Matrix profile**. Edit the prompt and choose **Ask Octos**. Back revokes the app session and interrupts its active turn. For `main.splash`, service callbacks receive `{is_ok, data, error}`. The source and its `{{assets}}` URLs follow the same entry contract as App Hub. Script apps own their state and callbacks; `bindings.json` is only for L0. -The importer currently accepts local unsigned bundles after explicit review. It does not install signed App Hub catalog packages or A2App `.splashapp` files. Room grants apply only to the room entered during review. Missing providers and failed calls are shown as errors. OS-specific services such as Mail account management are not exposed by this Rinx adapter. Bundle `agent` profiles are also rejected until all of their tool, budget and permission limits can be enforced. Octos service sessions explicitly narrow filesystem access to this app's data directory and disable tool network access. A remote standalone provider must be able to resolve that directory on its host; otherwise the core refuses the session. Bundled `os.*` system apps with an empty digest do not gain implicit trust when imported; a locally reviewed copy needs its digest generated. +The importer currently accepts local unsigned bundles after explicit review. It does not install signed App Hub catalog packages or A2App `.splashapp` files. Room grants apply only to the room entered during review. Missing providers and failed calls are shown as errors. OS-specific services such as Mail account management are not exposed by this Rinx adapter. Bundle `agent` profiles are also rejected until all of their tool, budget and permission limits can be enforced. Each running mini app gets its own kernel request context of Rinx's assistant peer: a separate transcript, a kernel-provisioned workspace inside Rinx's app workspace, and its own memory namespace (octos UPCR-2026-034). A remote server provisions that workspace itself; Rinx's local directories are never sent to it. Bundled `os.*` system apps with an empty digest do not gain implicit trust when imported; a locally reviewed copy needs its digest generated. ## Bind an event to a service @@ -35,6 +35,6 @@ cargo build --offline --manifest-path tools/miniapp-package/Cargo.toml tools/miniapp-package/target/debug/rinx-miniapp-package examples/miniapps/matrix-octos ``` -Each admitted instance runs from a verified snapshot. Editing the original package requires reviewing it again. Storage is confined to the current Matrix account and app ID. With a local shared core it lives beneath that core's configured data root, so session access can narrow the profile allowlist without widening it. Matrix-only / remote configurations use Rinx's data root. A custom core profile can still refuse the directory; Rinx does not relax that profile. +Each admitted instance runs from a verified snapshot. Editing the original package requires reviewing it again. Storage is confined to the current Matrix account and app ID. The isolate's storage lives in Rinx's data root; the assistant's workspace is the kernel's own for that request context. The kit files are from Octoscript revision `68f6a9df55692b5d8ef8873a12721e279a3f40d6`; their MIT license is included in `kit/LICENSE`. The Matrix contract and adapters derive from A2App revision `d4d39612fdee574a0f6a33480a19868f1ec85644`, under the license retained in `crates/miniapp-core/LICENSE-MIT`. diff --git a/src/app.rs b/src/app.rs index 3495321a..9658a016 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1317,6 +1317,10 @@ impl App { self.persist_runtime_state(cx, "shutdown"); + // Standalone exit: release the assistant and stop only a runtime + // Rinx owns (a remote server or OctoSense's kernel keeps running). + crate::octos_service::shutdown(); + if let Err(_e) = crate::sliding_sync::stop_sync_service_for_shutdown(Duration::from_secs(3)) { error!("Failed to stop Matrix sync service before shutdown. Error: Timed out."); } diff --git a/src/lib.rs b/src/lib.rs index 75e94ec7..1b18c7f7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -64,6 +64,7 @@ pub mod block_user_modal; pub mod shared; pub mod mini_app; pub mod octoscript_apps; +pub mod octos_service; pub mod article_app; pub mod forwarding; pub mod moments; diff --git a/src/module.rs b/src/module.rs index a0d92256..f63c15d2 100644 --- a/src/module.rs +++ b/src/module.rs @@ -91,7 +91,15 @@ pub static RINX_MODULE: RinxModule = RinxModule; impl AppModule for RinxModule { fn id(&self) -> &'static str { "rinx" } fn label(&self) -> &'static str { "Rinx" } - fn capabilities(&self) -> &'static [&'static str] { &["net", "storage", "audio.output", "clipboard"] } + /// The host reads Rinx's assistant needs from here (ADR 0007): the exact + /// App Hub `octos.*` service names its mini-app host serves. Declaring + /// them grants nothing; the host intersects them with its policy. + fn capabilities(&self) -> &'static [&'static str] { + &[ + "net", "storage", "audio.output", "clipboard", + "octos.session.open", "octos.session.history", "octos.turn.start", "octos.turn.interrupt", + ] + } fn open_schema(&self) -> OpenSchema { OpenSchema::new(1) } fn register(&self, vm: &mut ScriptVm) { @@ -101,6 +109,15 @@ impl AppModule for RinxModule { fn create(&self, vm: &mut ScriptVm, _open: ValidatedOpen, handles: InstanceHandles) -> InstanceParts { let owns_runtime = INSTANCE_ACTIVE.compare_exchange(false, true, Ordering::AcqRel, Ordering::Acquire).is_ok(); + // Hosted mode comes from the shell creating this module: take the + // scoped assistant service it offered to THIS instance, if any. No + // fallback kernel, no credentials, no AppCard. + let assistant = octosense_app_peers::injection::claim(self.id(), &handles.scope.to_string()); + if owns_runtime { + crate::octos_service::install_hosted(assistant); + } else if let Some(service) = assistant { + service.release(); + } let value = script_eval!(vm, { mod.widgets.RinxModuleView {} }); let root = WidgetRef::script_from_value(vm, value); if let Some(mut view) = root.borrow_mut::() { diff --git a/src/octos_service.rs b/src/octos_service.rs new file mode 100644 index 00000000..722330fa --- /dev/null +++ b/src/octos_service.rs @@ -0,0 +1,422 @@ +//! Where Rinx's assistant comes from (ADR 0007). +//! +//! | Deployment | Selected by | Runtime owner | +//! | --- | --- | --- | +//! | Hosted | the OctoSense shell creating the native module ([`install_hosted`]) | OctoSense | +//! | Standalone local | Rinx's AI settings ([`use_local`]) | Rinx | +//! | Standalone remote | an explicit server in Rinx's AI settings ([`use_remote`]) | the server | +//! +//! Every mode hands Rinx the same scoped [`OctosAppService`]: Rinx's peer +//! (owned by the OctoSense system agent when hosted, by Rinx's own root +//! session otherwise) with one request context per mini-app instance. Hosted +//! mode never starts a kernel, holds no AI credentials and cannot switch to +//! local or remote from Rinx's settings; a hosted Rinx without an injected +//! service simply has no assistant. An unconfigured assistant is a normal +//! state: Matrix and the editors keep working. + +use std::sync::{Arc, Mutex}; + +use octosense_app_peers::{Availability, Deployment, OctosAppService, SettingsEntry}; + +/// The standalone assistant mode, persisted (non-secret) in Rinx's data dir. +#[derive(Clone, Debug, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +#[serde(tag = "mode", rename_all = "snake_case")] +pub enum StandaloneMode { + /// No assistant. + #[default] + Off, + /// Rinx's own local runtime. + Local, + /// An explicit remote server. The access token is never written to disk: + /// it is asked for again after a restart. + Remote { url: String, profile: String }, +} + +#[derive(Default)] +struct State { + /// `Some` once the deployment is fixed; hosted is fixed for the process. + hosted: bool, + service: Option>, + mode: Option, +} + +static STATE: Mutex = Mutex::new(State { hosted: false, service: None, mode: None }); + +fn state() -> std::sync::MutexGuard<'static, State> { + STATE.lock().unwrap_or_else(|e| e.into_inner()) +} + +/// The OctoSense shell created Rinx as a native module and injected +/// `service` (or none: the host granted no assistant). Hosted is final. +pub fn install_hosted(service: Option>) { + let previous = { + let mut st = state(); + st.hosted = true; + st.mode = None; + std::mem::replace(&mut st.service, service) + }; + if let Some(previous) = previous { + previous.release(); + } + sync_account(); +} + +/// Whether the shell hosts Rinx's assistant. +pub fn is_hosted() -> bool { + state().hosted +} + +/// The current service, building the standalone one from its saved mode on +/// first use. `Err` says why there is no assistant. +pub fn service() -> Result, String> { + let (hosted, current, mode) = { + let st = state(); + (st.hosted, st.service.clone(), st.mode.clone()) + }; + if let Some(current) = current { + return Ok(current); + } + if hosted { + return Err("OctoSense has not given Rinx assistant access. \ + Check Settings → Accounts → AI providers." + .into()); + } + let mode = mode.unwrap_or_else(load_mode); + match mode { + StandaloneMode::Off => Err("The assistant is off. Choose this device or a server \ + in the assistant settings." + .into()), + StandaloneMode::Local => { + #[cfg(feature = "octos-local")] + { + install_standalone(local::service()?, StandaloneMode::Local); + service() + } + #[cfg(not(feature = "octos-local"))] + Err("This build has no local assistant runtime".into()) + } + StandaloneMode::Remote { .. } => { + Err("Enter the server's access token again to reconnect".into()) + } + } +} + +/// What to show about the assistant. +pub fn status() -> String { + let service = service(); + let service = match service { + Ok(service) => service, + Err(reason) => return reason, + }; + let owner = match service.deployment() { + Deployment::Hosted => "OctoSense", + Deployment::StandaloneLocal => "this device", + Deployment::StandaloneRemote => "your server", + }; + let model = service + .model() + .map(|m| match (m.provider, m.model) { + (Some(p), Some(model)) => format!(" · {p}/{model}"), + _ => format!(" · {}", m.lane), + }) + .unwrap_or_default(); + let state = match service.availability() { + Availability::Ready => "ready".to_owned(), + Availability::Idle => "starts on first use".to_owned(), + Availability::Unavailable(why) => why, + Availability::Failed(why) => format!("failed: {why}"), + }; + let settings = match service.settings_entry() { + SettingsEntry::Host => " · AI settings: OctoSense Settings → Accounts → AI providers", + SettingsEntry::AppLocal | SettingsEntry::AppRemote => "", + }; + format!("Assistant ({owner}){model}: {state}{settings}") +} + +/// Bind the logged-in Matrix account (called on every account change): the +/// previous account's requests are revoked and never restored under another. +pub fn sync_account() { + let service = state().service.clone(); + if let Some(service) = service { + let account = crate::sliding_sync::current_user_id().map(|u| u.to_string()); + service.set_account(account.as_deref()); + } +} + +/// Hosted Rinx is closing: release its leases, leave the shared kernel. +pub fn release() { + let service = state().service.take(); + if let Some(service) = service { + service.release(); + } +} + +/// Standalone Rinx is exiting: release, and stop only a runtime Rinx owns. +pub fn shutdown() { + let service = state().service.take(); + if let Some(service) = service { + service.shutdown(); + } +} + +/// Turn the standalone assistant off (stopping an owned runtime). +pub fn turn_off() -> Result<(), String> { + if is_hosted() { + return Err("OctoSense manages the assistant here".into()); + } + shutdown(); + save_mode(&StandaloneMode::Off)?; + state().mode = Some(StandaloneMode::Off); + Ok(()) +} + +#[allow(dead_code)] +fn install_standalone(service: Arc, mode: StandaloneMode) { + let previous = { + let mut st = state(); + st.mode = Some(mode); + std::mem::replace(&mut st.service, Some(service)) + }; + // Replacing a provider revokes the old one's requests first. + if let Some(previous) = previous { + previous.shutdown(); + } + sync_account(); +} + +fn settings_path() -> std::path::PathBuf { + crate::app_data_dir().join("octos").join("assistant.json") +} + +fn load_mode() -> StandaloneMode { + std::fs::read(settings_path()) + .ok() + .and_then(|bytes| serde_json::from_slice(&bytes).ok()) + .unwrap_or_default() +} + +fn save_mode(mode: &StandaloneMode) -> Result<(), String> { + let path = settings_path(); + if let Some(dir) = path.parent() { + std::fs::create_dir_all(dir).map_err(|e| e.to_string())?; + } + let bytes = serde_json::to_vec_pretty(mode).map_err(|e| e.to_string())?; + std::fs::write(&path, bytes).map_err(|e| e.to_string()) +} + +/// The services Rinx's peer uses: the four the mini-app host adapts. +#[cfg_attr(not(any(feature = "octos-local", feature = "octos-remote")), allow(dead_code))] +fn rinx_services() -> std::collections::BTreeSet { + octosense_app_peers::OCTOS_SERVICES.iter().map(|s| s.to_string()).collect() +} + +/// Rinx's root session in standalone modes: the owner of Rinx's peer. No +/// OctoSense system agent is manufactured; Rinx's agent is the app root. +#[allow(dead_code)] +fn standalone_root(profile: &str) -> String { + format!("{profile}:api:rinx#root") +} + +/// Use Rinx's own local runtime. +#[cfg(feature = "octos-local")] +pub fn use_local() -> Result<(), String> { + if is_hosted() { + return Err("OctoSense manages the assistant here".into()); + } + let service = local::service()?; + save_mode(&StandaloneMode::Local)?; + install_standalone(service, StandaloneMode::Local); + Ok(()) +} + +/// Save a provider for the local runtime (written into Rinx's own kernel +/// profile; never another installation's). Restarts an owned runtime so it +/// reads the new profile. +#[cfg(feature = "octos-local")] +pub fn configure_local_provider(family: &str, model: &str, base_url: &str, key: &str) -> Result<(), String> { + if is_hosted() { + return Err("OctoSense manages the assistant here".into()); + } + local::write_provider(family, model, base_url, key)?; + // The next request starts a runtime that reads the new provider. + shutdown(); + use_local() +} + +/// A fresh standalone-local service (Rinx-owned runtime), not installed. +/// For embedders and the process-level tests; the UI uses [`use_local`]. +#[cfg(feature = "octos-local")] +pub fn local_service() -> Result, String> { + local::service() +} + +/// Rinx's own local kernel root. +#[cfg(feature = "octos-local")] +pub fn local_core_dir() -> std::path::PathBuf { + local::core_dir() +} + +/// Write the local runtime's provider without switching modes. +#[cfg(feature = "octos-local")] +pub fn write_local_provider(family: &str, model: &str, base_url: &str, key: &str) -> Result<(), String> { + local::write_provider(family, model, base_url, key) +} + +/// Use an explicit remote octos server. The token stays in memory. +#[cfg(feature = "octos-remote")] +pub fn use_remote(url: &str, profile: &str, token: &str) -> Result<(), String> { + use octosense_app_peers::broker::{Broker, BrokerConfig}; + use octosense_app_peers::connectors::WsConnector; + if is_hosted() { + return Err("OctoSense manages the assistant here".into()); + } + let url = url::Url::parse(url.trim()).map_err(|_| "Enter a complete server URL")?; + let profile = profile.trim(); + if profile.is_empty() { + return Err("Enter the server's profile name".into()); + } + if token.is_empty() { + return Err("Enter the server's access token".into()); + } + let connector = WsConnector::new(url.clone(), token, profile)?; + let cfg = BrokerConfig::new( + Deployment::StandaloneRemote, + profile, + standalone_root(profile), + "rinx", + "Rinx", + rinx_services(), + ); + let service = Arc::new(Broker::new(cfg, Arc::new(connector))); + let mode = StandaloneMode::Remote { url: url.to_string(), profile: profile.to_owned() }; + save_mode(&mode)?; + install_standalone(service, mode); + Ok(()) +} + +/// The saved remote server, to prefill the form. +pub fn saved_remote() -> Option<(String, String)> { + match load_mode() { + StandaloneMode::Remote { url, profile } => Some((url, profile)), + _ => None, + } +} + +#[cfg(feature = "octos-local")] +mod local { + use super::*; + use octosense_app_peers::broker::{Broker, BrokerConfig}; + use octosense_app_peers::connectors::CoreConnector; + use std::path::PathBuf; + + /// Rinx's own kernel root, independent of any OctoSense installation or + /// desktop octos profile. + pub(super) fn core_dir() -> PathBuf { + crate::app_data_dir().join("octos").join(".octos") + } + + /// The packaged kernel: `RINX_OCTOS_BIN` when a developer sets it + /// explicitly, else `octos` beside the Rinx executable (inside the app + /// bundle on macOS). Never looked up on PATH. Android uses the APK's + /// bundled `liboctos.so` (octosense-octos-core resolves it). + fn packaged_kernel() -> Option { + if let Some(explicit) = std::env::var_os("RINX_OCTOS_BIN") { + return Some(PathBuf::from(explicit)); + } + if cfg!(target_os = "android") { + return None; + } + let exe = std::env::current_exe().ok()?; + let dir = exe.parent()?; + let name = if cfg!(windows) { "octos.exe" } else { "octos" }; + [dir.join(name), dir.join("../Resources").join(name)] + .into_iter() + .find(|p| p.is_file()) + } + + pub(super) fn service() -> Result, String> { + let mut options = octosense_app_peers::octos_core::Options::default().core_dir(core_dir()); + match packaged_kernel() { + Some(program) => options = options.program(program), + None if cfg!(target_os = "android") => {} + None => { + return Err("This Rinx build has no packaged assistant runtime \ + (octos beside the executable)" + .into()) + } + } + let core = octosense_app_peers::octos_core::Core::new(options); + core.launch().map_err(|e| e.to_string())?; + let cfg = BrokerConfig::new( + Deployment::StandaloneLocal, + "_main", + standalone_root("_main"), + "rinx", + "Rinx", + rinx_services(), + ); + Ok(Arc::new(Broker::new(cfg, Arc::new(CoreConnector::owned(core))))) + } + + /// Write the local kernel's primary provider into Rinx's own profile. + pub(super) fn write_provider(family: &str, model: &str, base_url: &str, key: &str) -> Result<(), String> { + let family = family.trim(); + let model = model.trim(); + if family.is_empty() || model.is_empty() { + return Err("Enter the provider and the model".into()); + } + if !family.bytes().all(|b| b.is_ascii_alphanumeric() || b == b'-' || b == b'_') { + return Err("Unknown provider name".into()); + } + let dir = core_dir().join("profiles"); + std::fs::create_dir_all(&dir).map_err(|e| e.to_string())?; + let key_env = format!("{}_API_KEY", family.to_ascii_uppercase().replace('-', "_")); + let mut route = serde_json::json!({ "api_key_env": key_env }); + if !base_url.trim().is_empty() { + let url = url::Url::parse(base_url.trim()).map_err(|_| "Enter a complete base URL")?; + route["base_url"] = serde_json::json!(url.as_str()); + } + let now = chrono::Utc::now().to_rfc3339(); + let mut env = serde_json::Map::new(); + if !key.is_empty() { + env.insert(key_env.clone(), serde_json::json!(key)); + } + let profile = serde_json::json!({ + "id": "_main", "name": "Rinx", "enabled": true, + "created_at": now, "updated_at": now, + "config": { + "llm": {"primary": {"family_id": family, "model_id": model, "route": route}}, + "env_vars": env, + } + }); + let path = dir.join("_main.json"); + let tmp = dir.join("_main.json.tmp"); + std::fs::write(&tmp, serde_json::to_vec_pretty(&profile).map_err(|e| e.to_string())?) + .map_err(|e| e.to_string())?; + #[cfg(unix)] + { + use std::os::unix::fs::PermissionsExt; + let _ = std::fs::set_permissions(&tmp, std::fs::Permissions::from_mode(0o600)); + } + std::fs::rename(&tmp, &path).map_err(|e| e.to_string()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn standalone_mode_round_trips_without_secrets() { + let mode = StandaloneMode::Remote { url: "https://octos.example".into(), profile: "me".into() }; + let text = serde_json::to_string(&mode).unwrap(); + assert!(!text.contains("token")); + assert_eq!(serde_json::from_str::(&text).unwrap(), mode); + assert_eq!(serde_json::from_str::(r#"{"mode":"off"}"#).unwrap(), StandaloneMode::Off); + } + + #[test] + fn the_standalone_root_is_rinx_own_session() { + assert_eq!(standalone_root("_main"), "_main:api:rinx#root"); + } +} diff --git a/src/octoscript_apps/mod.rs b/src/octoscript_apps/mod.rs index 5c74d41c..50de4fc1 100644 --- a/src/octoscript_apps/mod.rs +++ b/src/octoscript_apps/mod.rs @@ -6,6 +6,9 @@ static AUTHORITY: LazyLock = LazyLock::new( pub fn invalidate_sessions() { AUTHORITY.invalidate(); + // Account change or logout: the assistant's contexts of the previous + // account are revoked too (ADR 0007). + crate::octos_service::sync_account(); } pub async fn matrix_request( @@ -20,7 +23,7 @@ pub async fn matrix_request( mod octos; mod package; pub mod ui; -pub use octos::KernelProvider; +pub use octos::ContextProvider; pub use ui::{MiniAppsAction, MiniAppsPanelWidgetRefExt}; pub fn script_mod(vm: &mut makepad_widgets::ScriptVm) { diff --git a/src/octoscript_apps/octos.rs b/src/octoscript_apps/octos.rs index 15f583ef..e541e0fa 100644 --- a/src/octoscript_apps/octos.rs +++ b/src/octoscript_apps/octos.rs @@ -1,63 +1,94 @@ -//! Octos adapter over the SAME connection AppCard publishes on its UI thread. -use octos_app_transport::shared::Connection; +//! Mini-app Octos services over Rinx's assistant (ADR 0007). +//! +//! Each running mini app gets its own request context of Rinx's peer +//! (`crate::octos_service`): a separate transcript, workspace and memory +//! namespace in the kernel. Never an ordinary privileged session, a kernel of +//! its own or a raw connection. +use octosense_app_peers::{ContextEvent, ContextOp, ContextSpec, OctosContext}; use rinx_miniapp_core::{InstanceId, Lease, OctosProvider, ServiceEvent}; use serde_json::{Value, json}; -use std::sync::{ - Arc, - atomic::{AtomicU64, Ordering}, - mpsc::SyncSender, -}; +use std::sync::{Arc, mpsc::SyncSender}; -pub struct KernelProvider { - connection: Arc, - session: String, - active_turn: Arc, - turn_namespace: u64, - workspace: Option, +/// One mini-app instance's Octos adapter. +pub struct ContextProvider { + context: Arc, } -impl KernelProvider { - pub fn shared(workspace: &std::path::Path) -> Result>, String> { - let Some(connection) = Connection::current() else { - return Ok(None); - }; - let workspace = workspace.canonicalize().map_err(|e| e.to_string())?; - Ok(Some(Self::from_connection( - connection, - Some(workspace.to_string_lossy().into_owned()), - ))) - } - fn from_connection(connection: Arc, workspace: Option) -> Arc { - static NEXT: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(1); - let nonce = std::time::SystemTime::now() - .duration_since(std::time::UNIX_EPOCH) - .unwrap_or_default() - .as_nanos(); - let id = NEXT.fetch_add(1, std::sync::atomic::Ordering::Relaxed); - let session = format!("{}:api:rinx-mini-{nonce:x}-{id}", connection.profile); - Arc::new(Self { - connection, - session, - active_turn: Arc::new(AtomicU64::new(0)), - turn_namespace: (uuid::Uuid::new_v4().as_u128() >> 64) as u64, - workspace, - }) - } - /// Explicit standalone configuration uses the identical WS/stdio protocol. - pub fn connect(config: octos_app_transport::TransportConfig) -> Result, String> { - let (connection, receiver) = - Connection::start(config, Arc::new(makepad_widgets::SignalToUI::set_ui_signal))?; - drop(receiver); - Ok(Self::from_connection(connection, None)) + +impl ContextProvider { + /// Open the instance's request context. `Err` names why the assistant is + /// unavailable; the mini app's other services keep working. + pub fn open(lease: &Lease) -> Result, String> { + let service = crate::octos_service::service()?; + let identity = lease.identity(); + let services = lease + .services() + .iter() + .filter(|s| octosense_app_peers::OCTOS_SERVICES.contains(&s.as_str())) + .cloned() + .collect(); + let context = service.open_context(ContextSpec { + account: identity.account.clone(), + instance: format!("{}-g{}", identity.app, identity.generation), + services, + })?; + Ok(Arc::new(Self { context })) } } -fn turn_id(namespace: u64, number: u64) -> String { - uuid::Uuid::from_u128(((namespace as u128) << 64) | number as u128).to_string() -} + fn valid(lease: &Lease) -> Result<(), String> { let account = crate::sliding_sync::current_user_id().ok_or("Not logged in")?; lease.check(account.as_str()) } -impl OctosProvider for KernelProvider { + +/// Turn a context event into the shape mini apps bind to: +/// `{"text", "event": {"kind", …}}`. +fn mini_app_value(data: &Value) -> Value { + let method = data["method"].as_str().unwrap_or(""); + let params = &data["params"]; + let event = match method { + "approval/requested" => json!({ + "kind": "approval_requested", + "approval_id": params["approval_id"], + "title": params["title"], + "body": params["body"], + }), + other => json!({"kind": other.replace('/', "_")}), + }; + json!({"text": data.get("text").cloned().unwrap_or(Value::Null), "event": event}) +} + +fn forward(lease: Lease, reply: SyncSender) -> octosense_app_peers::EventSink { + let reply = std::sync::Mutex::new(reply); + Arc::new(move |event| { + // The lease is checked again before anything reaches the app. + if valid(&lease).is_err() { + return; + } + let event = match event { + ContextEvent::Data(data) => { + // Streamed text and approval requests only. + if data.get("text").is_none() && data["method"] != "approval/requested" { + return; + } + match rinx_miniapp_core::bounded_reply(mini_app_value(&data)) { + Ok(value) => ServiceEvent::Data(value), + Err(_) => return, + } + } + ContextEvent::Complete(result) => ServiceEvent::Complete( + result + .map(|v| json!({"text": v.get("text").cloned().unwrap_or(v.clone()), "turn_id": v.get("turn_id")})) + .and_then(rinx_miniapp_core::bounded_reply), + ), + }; + if let Ok(reply) = reply.lock() { + let _ = reply.try_send(event); + } + makepad_widgets::SignalToUI::set_ui_signal(); + }) +} + +impl OctosProvider for ContextProvider { fn request( &self, lease: Lease, @@ -66,130 +97,32 @@ impl OctosProvider for KernelProvider { reply: SyncSender, ) -> Result<(), String> { valid(&lease)?; - let workspace = self - .workspace - .clone() - .ok_or("Open the mini app to bind its Octos workspace")?; - if !self.connection.is_active() { - return Err("Octos connection changed; reopen this app".into()); - } lease.authorize(&lease.identity().account, service, None)?; - let method = match service { - "octos.session.open" => "session/open", - "octos.session.history" => "session/hydrate", - "octos.turn.start" => "turn/start", - "octos.turn.interrupt" => "turn/interrupt", - _ => return Err("Unknown Octos mini-app service".into()), - }; // Apps supply input text, never session/profile/workspace identity, // approval decisions, arbitrary RPC methods or filesystem paths. - let allowed: &[&str] = if method == "turn/start" { - &["text"] - } else { - &[] - }; + let allowed: &[&str] = if service == "octos.turn.start" { &["text"] } else { &[] }; if args .as_object() .is_none_or(|o| o.keys().any(|k| !allowed.contains(&k.as_str()))) { return Err("Unsupported Octos arguments".into()); } - let session = self.session.clone(); - static NEXT_TURN: AtomicU64 = AtomicU64::new(1); - let turn_number = if method == "turn/start" { - NEXT_TURN.fetch_add(1, Ordering::Relaxed) - } else { - self.active_turn.load(Ordering::Acquire) - }; - if method == "turn/interrupt" && turn_number == 0 { - return Err("No active Octos turn".into()); - } - let turn = turn_id(self.turn_namespace, turn_number); - let params = match method { - "session/open" => json!({"session_id":session,"profile_id":self.connection.profile, - "cwd":workspace,"sandbox":{"enabled":true,"network_access":false,"read_allow_paths":[workspace]}}), - "session/hydrate" => json!({"session_id":session,"include":["messages"]}), - "turn/start" => { - let text = args["text"] + let op = match service { + "octos.session.open" => ContextOp::Open, + "octos.session.history" => ContextOp::History, + "octos.turn.start" => ContextOp::Turn { + text: args["text"] .as_str() .filter(|s| !s.trim().is_empty() && s.len() <= 32 * 1024) - .ok_or("Provide text (at most 32 KiB)")?; - json!({"session_id":session,"turn_id":turn,"input":[{"kind":"text","text":text}]}) - } - _ => json!({"session_id":session,"turn_id":turn}), + .ok_or("Provide text (at most 32 KiB)")? + .to_owned(), + }, + "octos.turn.interrupt" => ContextOp::Interrupt, + _ => return Err("Unknown Octos mini-app service".into()), }; - if method == "turn/start" - && self - .active_turn - .compare_exchange(0, turn_number, Ordering::AcqRel, Ordering::Acquire) - .is_err() - { - return Err("This app already has an active Octos turn".into()); - } - let active_turn = self.active_turn.clone(); - let connection = self.connection.clone(); - self.connection.handle().spawn(async move { - let mut events = connection.subscribe(); - let work = async { - valid(&lease)?; - if matches!(method,"turn/start"|"session/hydrate") { - connection.request("session/open",json!({"session_id":session,"profile_id":connection.profile, - "cwd":workspace,"sandbox":{"enabled":true,"network_access":false,"read_allow_paths":[workspace]}})).await?; - } - let result = connection.request(method, params).await?; - valid(&lease)?; - if method != "turn/start" { return Ok(result); } - let mut stream = TurnReply::default(); - loop { - let event = events.recv().await.map_err(|_| "Octos event stream closed or fell behind; reload history")?; - if event.session_id().0 != session { continue; } - let data = serde_json::to_value(&*event).map_err(|e| e.to_string())?; - valid(&lease)?; - if !stream.accept(&turn, &data)? {continue;} - if stream.completed { - // The terminal can overtake the persisted transcript lane. - // Hydrate by THIS turn, never substitute an older answer. - let history=connection.request("session/hydrate",json!({"session_id":session,"include":["messages"]})).await?; - valid(&lease)?; - if let Some(text)=history["messages"].as_array().and_then(|rows|rows.iter().rev().find(|m|m["role"]=="assistant" && m["turn_id"]==turn)).and_then(|m|m["content"].as_str()) { - stream.text=text.to_owned(); - } - return rinx_miniapp_core::bounded_reply(json!({"text":stream.text,"event":data})); - } - let data=rinx_miniapp_core::bounded_reply(json!({"text":stream.text,"event":data}))?; - reply.try_send(ServiceEvent::Data(data)).map_err(|_| "Mini-app event consumer is unavailable")?; - makepad_widgets::SignalToUI::set_ui_signal(); - } - }; - tokio::pin!(work); - let timeout = tokio::time::sleep(std::time::Duration::from_secs(180)); - tokio::pin!(timeout); - let result = loop { - tokio::select! { - r = &mut work => break r, - _ = &mut timeout => break Err("Octos turn timed out".into()), - _ = tokio::time::sleep(std::time::Duration::from_millis(100)) => { - if let Err(e) = valid(&lease) { break Err(e); } - if !connection.is_active() { break Err("Octos connection changed".into()); } - } - } - }; - if result.is_err() && method == "turn/start" { - let _ = connection.request("turn/interrupt", json!({"session_id":session,"turn_id":turn})).await; - } - if method=="turn/start" { let _=active_turn.compare_exchange(turn_number,0,Ordering::AcqRel,Ordering::Acquire); } - let result = result.map_err(|error| { - if error.contains("401") && error.to_ascii_lowercase().contains("authentication") { - "Octos provider authentication failed (HTTP 401). Update the provider credentials in AppCard.".into() - } else { - error - } - }); - let _ = reply.try_send(ServiceEvent::Complete(result)); - makepad_widgets::SignalToUI::set_ui_signal(); - }); - Ok(()) + self.context.call(op, forward(lease, reply)) } + fn decide( &self, lease: Lease, @@ -198,229 +131,31 @@ impl OctosProvider for KernelProvider { reply: SyncSender, ) -> Result<(), String> { valid(&lease)?; - let connection = self.connection.clone(); - let params = json!({"session_id":self.session,"approval_id":approval,"decision":if approve{"approve"}else{"deny"}}); - self.connection.handle().spawn(async move { - let result = async { - valid(&lease)?; - let result = connection.request("approval/respond", params).await?; - valid(&lease)?; - Ok(result) - } - .await; - let _ = reply.try_send(ServiceEvent::Complete(result)); - makepad_widgets::SignalToUI::set_ui_signal(); - }); - Ok(()) + self.context.call( + ContextOp::Approval { id: approval.to_owned(), approve }, + forward(lease, reply), + ) } + fn close(&self, _identity: &InstanceId) { - let number = self.active_turn.load(Ordering::Acquire); - if number == 0 { - return; - } - let connection = self.connection.clone(); - let session = self.session.clone(); - let turn = turn_id(self.turn_namespace, number); - self.connection.handle().spawn(async move { - let _ = connection - .request( - "turn/interrupt", - json!({"session_id":session,"turn_id":turn}), - ) - .await; - }); + self.context.close(); } } -/// Consume both protocol generations while keeping turn and segment ownership. -#[derive(Default)] -struct TurnReply { - text: String, - segment: String, - sequence: std::collections::BTreeMap, - persisted_segments: std::collections::BTreeSet, - v2: bool, - completed: bool, -} -impl TurnReply { - fn accept(&mut self, turn: &str, event: &Value) -> Result { - let envelope = &event["envelope"]; - let event_turn = event - .get("turn_id") - .or_else(|| envelope.get("turn_id")) - .and_then(Value::as_str); - if event_turn.is_some_and(|id| id != turn) { - return Ok(false); - } - match event["kind"].as_str().unwrap_or("") { - "envelope_v2" => { - if event_turn != Some(turn) { - return Ok(false); - } - if let (Some(thread), Some(seq)) = - (envelope["thread_id"].as_str(), envelope["seq"].as_u64()) - { - if self.sequence.get(thread).is_some_and(|seen| seq <= *seen) { - return Ok(false); - } - self.sequence.insert(thread.to_owned(), seq); - } - let payload = &envelope["payload"]; - let data = &payload["data"]; - match payload["type"].as_str().unwrap_or("") { - "assistant_delta" | "assistant_persisted" => { - let segment = data["assistant_segment_id"].as_str().unwrap_or(""); - // Persistence and live deltas travel on separate core - // lanes. A complete saved answer may precede higher- - // sequence deltas for the same segment; those fragments - // are already included in the saved text. - if payload["type"] == "assistant_delta" - && self.persisted_segments.contains(segment) - { - return Ok(false); - } - if !self.v2 || self.segment != segment { - self.text.clear(); - self.segment = segment.into(); - } - self.v2 = true; - let text = data["text"].as_str().unwrap_or(""); - if payload["type"] == "assistant_persisted" { - self.persisted_segments.insert(segment.to_owned()); - self.text = text.into(); - } else { - self.text.push_str(text); - } - } - "turn_terminal" => { - if data["outcome"] != "completed" { - return Err(data["error"]["message"] - .as_str() - .unwrap_or("Octos turn ended without completing") - .to_owned()); - } - self.completed = true; - } - _ => {} - } - } - "message_delta" if !self.v2 => self.text.push_str(event["text"].as_str().unwrap_or("")), - "turn_completed" => self.completed = true, - "turn_error" => { - return Err(event["message"] - .as_str() - .unwrap_or("Octos turn failed") - .into()); - } - _ => {} - } - Ok(true) - } -} #[cfg(test)] mod tests { use super::*; - #[test] - fn persisted_answers_ignore_late_deltas_without_blocking_new_segments() { - let mut reply = TurnReply::default(); - let event = |seq, kind, segment, text| { - json!({"kind":"envelope_v2","envelope":{ - "turn_id":"owned","thread_id":"thread","seq":seq, - "payload":{"type":kind,"data":{ - "assistant_segment_id":segment,"text":text - }} - }}) - }; - reply - .accept("owned", &event(1, "assistant_delta", "first", "Hello")) - .unwrap(); - reply - .accept( - "owned", - &event(2, "assistant_persisted", "first", "Hello! How can I help?"), - ) - .unwrap(); - assert!( - !reply - .accept( - "owned", - &event(3, "assistant_delta", "first", "! How can I help?") - ) - .unwrap() - ); - assert_eq!(reply.text, "Hello! How can I help?"); - assert!( - reply - .accept( - "owned", - &event(4, "assistant_delta", "next", "Another answer") - ) - .unwrap() - ); - assert!( - !reply - .accept( - "owned", - &event(5, "assistant_delta", "first", "late old fragment") - ) - .unwrap() - ); - assert_eq!(reply.text, "Another answer"); - reply - .accept( - "owned", - &event(6, "assistant_persisted", "next", "Another answer."), - ) - .unwrap(); - assert!( - !reply - .accept("owned", &event(7, "assistant_delta", "next", ".")) - .unwrap() - ); - assert_eq!(reply.text, "Another answer."); - } #[test] - fn v2_final_replaces_deltas_and_ignores_other_turns_and_replay() { - let mut reply = TurnReply::default(); - assert!( - !reply - .accept( - "owned", - &json!({"kind":"message_delta","turn_id":"other","text":"private"}) - ) - .unwrap() - ); - reply - .accept( - "owned", - &json!({"kind":"message_delta","turn_id":"owned","text":"draft"}), - ) - .unwrap(); - let event = json!({"kind":"envelope_v2","envelope":{"turn_id":"owned","thread_id":"thread","seq":1,"payload":{"type":"assistant_persisted","data":{"text":"final answer","assistant_segment_id":"segment"}}}}); - assert!(reply.accept("owned", &event).unwrap()); - assert!(!reply.accept("owned", &event).unwrap()); - assert_eq!(reply.text, "final answer"); - reply - .accept( - "owned", - &json!({"kind":"message_delta","turn_id":"owned","text":"duplicate"}), - ) - .unwrap(); - assert_eq!(reply.text, "final answer"); - assert!( - reply - .accept( - "owned", - &json!({"kind":"turn_error","turn_id":"owned","message":"denied"}) - ) - .is_err() - ); - } - #[test] - fn host_turn_ids_are_protocol_uuids() { - assert!(uuid::Uuid::parse_str(&turn_id(123, 1)).is_ok()); - assert_ne!(turn_id(123, 1), turn_id(123, 2)); - assert_ne!(turn_id(123, 1), turn_id(124, 1)); + fn approval_requests_keep_the_shape_the_native_prompt_reads() { + let value = mini_app_value(&json!({ + "method": "approval/requested", + "params": {"approval_id": "a1", "title": "Run shell", "body": "ls"}, + })); + assert_eq!(value["event"]["kind"], "approval_requested"); + assert_eq!(value["event"]["approval_id"], "a1"); + let streamed = mini_app_value(&json!({"method": "projection/envelope", "params": {}, "text": "Hel"})); + assert_eq!(streamed["text"], "Hel"); + assert_eq!(streamed["event"]["kind"], "projection_envelope"); } } diff --git a/src/octoscript_apps/ui.rs b/src/octoscript_apps/ui.rs index 311fbd25..6bfae50d 100644 --- a/src/octoscript_apps/ui.rs +++ b/src/octoscript_apps/ui.rs @@ -1,6 +1,6 @@ //! One native mini-app screen shared by standalone and embedded Rinx. use super::{ - InstanceId, KernelProvider, Lease, OctosProvider, ServiceEvent, + ContextProvider, InstanceId, Lease, OctosProvider, ServiceEvent, package::{Call, Package}, }; use makepad_widgets::splash_host::{splash_host_respond, take_splash_host_requests_for}; @@ -36,7 +36,16 @@ script_mod! { import_form := View {width: Fill height: Fit flow: Down spacing: 8 path := TextInput {width: Fill empty_text: "OctoSense bundle folder"} room := TextInput {width: Fill empty_text: "Room ID to allow (optional)"} + assistant_status := Label {width: Fill draw_text.color: #555 text: ""} core := View {width: Fill height: Fit flow: Down spacing: 6 + local_family := TextInput {width: Fill empty_text: "Assistant on this device: provider (e.g. deepseek)"} + local_model := TextInput {width: Fill empty_text: "Model"} + local_base_url := TextInput {width: Fill empty_text: "Base URL (optional)"} + local_key := TextInput {width: Fill is_password: true empty_text: "API key (kept in Rinx's own runtime)"} + local_buttons := View {width: Fill height: Fit spacing: 8 + use_local := Button {text: "Use this device"} + turn_off := Button {text: "Turn assistant off"} + } endpoint := TextInput {width: Fill empty_text: "Octos server URL"} profile := TextInput {width: Fill empty_text: "Octos profile"} token := TextInput {width: Fill is_password: true empty_text: "Octos access token"} @@ -83,10 +92,10 @@ pub struct MiniAppsPanel { #[rust] lease: Option, #[rust] - connection_owner: Option, - #[rust] provider: Option, #[rust] + octos_unavailable: Option, + #[rust] tag: String, #[rust] state: InstanceStore, @@ -137,51 +146,55 @@ impl MiniAppsPanel { .view(cx, ids!(approval)) .set_visible(cx, !self.approvals.is_empty()); } + fn show_assistant_status(&mut self, cx: &mut Cx) { + let status = crate::octos_service::status(); + self.view + .label(cx, ids!(import_form.assistant_status)) + .set_text(cx, &status); + } + /// An explicit remote server (standalone only; hosted Rinx uses + /// OctoSense's AI settings and offers no endpoint or key form). + #[cfg_attr(not(feature = "octos-remote"), allow(unused_variables))] fn connect(&mut self, cx: &mut Cx) -> Result<(), String> { - #[cfg(feature = "octosense-module")] - if crate::module::is_hosted() { - return Err("This app uses OctoSense's core connection".into()); - } - let endpoint = self - .view - .text_input(cx, ids!(import_form.core.endpoint)) - .text(); - let url = - url::Url::parse(endpoint.trim()).map_err(|_| "Enter a complete Octos server URL")?; - if !matches!(url.scheme(), "http" | "https") - || url.host_str().is_none() - || !url.username().is_empty() - || url.password().is_some() + if crate::octos_service::is_hosted() { + return Err("This app uses OctoSense's AI settings".into()); + } + #[cfg(feature = "octos-remote")] { - return Err("Use an HTTP or HTTPS URL without embedded credentials".into()); - } - let profile = self - .view - .text_input(cx, ids!(import_form.core.profile)) - .text(); - if profile.trim().is_empty() { - return Err("Enter the Octos profile name".into()); - } - let token = self - .view - .text_input(cx, ids!(import_form.core.token)) - .text(); - let provider = KernelProvider::connect(octos_app_transport::TransportConfig { - base_url: url, - bearer: octos_app_transport::SecretString::new(token), - profile_id: octos_app_transport::ProfileId::new(profile.trim()), - cursor: None, - cursor_file: None, - requested_capabilities: octos_app_transport::Capabilities::requested(), - workspace_cwd: None, - stdio: None, - })?; - self.connection_owner = Some(provider); - self.view - .text_input(cx, ids!(import_form.core.token)) - .set_text(cx, ""); - self.notice(cx, "Octos connection configured. Review and run your app."); - Ok(()) + let endpoint = self.view.text_input(cx, ids!(import_form.core.endpoint)).text(); + let profile = self.view.text_input(cx, ids!(import_form.core.profile)).text(); + let token = self.view.text_input(cx, ids!(import_form.core.token)).text(); + crate::octos_service::use_remote(&endpoint, &profile, &token)?; + self.view.text_input(cx, ids!(import_form.core.token)).set_text(cx, ""); + self.show_assistant_status(cx); + Ok(()) + } + #[cfg(not(feature = "octos-remote"))] + Err("This build cannot connect to an Octos server".into()) + } + /// Rinx's own local runtime, optionally with a new provider. + #[cfg_attr(not(feature = "octos-local"), allow(unused_variables))] + fn use_local(&mut self, cx: &mut Cx) -> Result<(), String> { + if crate::octos_service::is_hosted() { + return Err("This app uses OctoSense's AI settings".into()); + } + #[cfg(feature = "octos-local")] + { + let family = self.view.text_input(cx, ids!(import_form.core.local_family)).text(); + let model = self.view.text_input(cx, ids!(import_form.core.local_model)).text(); + let base = self.view.text_input(cx, ids!(import_form.core.local_base_url)).text(); + let key = self.view.text_input(cx, ids!(import_form.core.local_key)).text(); + if family.trim().is_empty() && model.trim().is_empty() { + crate::octos_service::use_local()?; + } else { + crate::octos_service::configure_local_provider(&family, &model, &base, &key)?; + } + self.view.text_input(cx, ids!(import_form.core.local_key)).set_text(cx, ""); + self.show_assistant_status(cx); + Ok(()) + } + #[cfg(not(feature = "octos-local"))] + Err("This build has no local assistant runtime".into()) } fn review(&mut self, cx: &mut Cx) -> Result<(), String> { self.stop(cx); @@ -247,15 +260,24 @@ impl MiniAppsPanel { // The local core's default read boundary is its data root. Allocate // an account/app child there and then narrow the session to that child. // The location comes from the native host, never from bundle input. - let root = octos_app_transport::shared::Connection::current() - .and_then(|c| c.local_data_root.clone()) - .unwrap_or_else(|| crate::app_data_dir().to_owned()) - .join("miniapps") - .join(account_dir); + // The isolate's own storage stays in Rinx's data dir; the assistant's + // workspace for this instance is its kernel request context's. + let root = crate::app_data_dir().join("miniapps").join(account_dir); let mut settings = package.policy.isolate_settings(&root); std::fs::create_dir_all(&settings.jail_root).map_err(|e| e.to_string())?; - self.provider = - KernelProvider::shared(&settings.jail_root)?.map(|p| p as Arc); + let wants_octos = package + .manifest + .capabilities + .iter() + .any(|c| octosense_app_peers::OCTOS_SERVICES.contains(&c.as_str())); + self.provider = None; + self.octos_unavailable = None; + if wants_octos { + match ContextProvider::open(&lease) { + Ok(provider) => self.provider = Some(provider as Arc), + Err(reason) => self.octos_unavailable = Some(reason), + } + } settings.hosts.push(server.allowlist_entry()); settings.allow_net = true; if !package.script { @@ -352,8 +374,15 @@ impl MiniAppsPanel { let _ = tx.try_send(ServiceEvent::Complete(result)); SignalToUI::set_ui_signal(); }); - } else if service.starts_with("octos.") { - self.provider.as_ref().ok_or("Octos unavailable. Open AppCard in OctoSense to connect the core, then reopen this mini app.")?.request(lease,service,args,tx)?; + } else if octosense_app_peers::OCTOS_SERVICES.contains(&service) { + let unavailable = self + .octos_unavailable + .clone() + .unwrap_or_else(|| "The assistant is unavailable".into()); + self.provider + .as_ref() + .ok_or(unavailable)? + .request(lease, service, args, tx)?; } else { return Err(format!("No adapter for {service}")); } @@ -586,6 +615,12 @@ impl Widget for MiniAppsPanel { .clicked(actions) { self.connect(cx) + } else if self.view.button(cx, ids!(import_form.core.local_buttons.use_local)).clicked(actions) { + self.use_local(cx) + } else if self.view.button(cx, ids!(import_form.core.local_buttons.turn_off)).clicked(actions) { + let result = crate::octos_service::turn_off(); + self.show_assistant_status(cx); + result } else if self.view.button(cx, ids!(review)).clicked(actions) { self.review(cx) } else if self.view.button(cx, ids!(run)).clicked(actions) { @@ -615,11 +650,13 @@ impl MiniAppsPanelRef { MiniAppsAction::Open => { inner.open = true; inner.notice(cx, "Import an OctoSense bundle to review its services."); - #[cfg(feature = "octosense-module")] + inner.show_assistant_status(cx); + // Hosted Rinx uses OctoSense's AI settings: no endpoint + // or key form of its own. inner .view .view(cx, ids!(import_form.core)) - .set_visible(cx, !crate::module::is_hosted()); + .set_visible(cx, !crate::octos_service::is_hosted()); modal.open(cx); } MiniAppsAction::Close => { diff --git a/tests/fixtures/mock_llm.py b/tests/fixtures/mock_llm.py new file mode 100644 index 00000000..2fec7fd4 --- /dev/null +++ b/tests/fixtures/mock_llm.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python3 +"""A scripted OpenAI-compatible model for kernel tests. No network, no keys. + +POST /v1/chat/completions answers "ECHO: ". A user text that +contains SLOW waits 20 s first (for revocation tests). Prints its port on the +first line of stdout, then serves until killed. Standard library only. +""" +import json +import sys +import time +from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer + + +def last_user_text(body): + for message in reversed(body.get("messages", [])): + if message.get("role") == "user": + content = message.get("content") + if isinstance(content, list): + return " ".join(p.get("text", "") for p in content if isinstance(p, dict)) + return content or "" + return "" + + +class Handler(BaseHTTPRequestHandler): + def log_message(self, *args): + pass + + def do_GET(self): + if self.path.endswith("/models"): + self._json({"object": "list", "data": [{"id": "mock-model", "object": "model"}]}) + else: + self.send_error(404) + + def do_POST(self): + length = int(self.headers.get("content-length", "0")) + body = json.loads(self.rfile.read(length) or b"{}") + text = last_user_text(body) + if "SLOW" in text: + time.sleep(20) + reply = "ECHO: " + text.strip().splitlines()[-1] if text.strip() else "ECHO:" + if body.get("stream"): + self.send_response(200) + self.send_header("content-type", "text/event-stream") + self.end_headers() + for chunk in [reply[: len(reply) // 2], reply[len(reply) // 2 :]]: + event = {"id": "c1", "object": "chat.completion.chunk", "model": "mock-model", + "choices": [{"index": 0, "delta": {"role": "assistant", "content": chunk}, "finish_reason": None}]} + self.wfile.write(b"data: " + json.dumps(event).encode() + b"\n\n") + done = {"id": "c1", "object": "chat.completion.chunk", "model": "mock-model", + "choices": [{"index": 0, "delta": {}, "finish_reason": "stop"}], + "usage": {"prompt_tokens": 10, "completion_tokens": 5, "total_tokens": 15}} + self.wfile.write(b"data: " + json.dumps(done).encode() + b"\n\n") + self.wfile.write(b"data: [DONE]\n\n") + self.wfile.flush() + else: + self._json({"id": "c1", "object": "chat.completion", "model": "mock-model", + "choices": [{"index": 0, "message": {"role": "assistant", "content": reply}, "finish_reason": "stop"}], + "usage": {"prompt_tokens": 10, "completion_tokens": 5, "total_tokens": 15}}) + + def _json(self, value): + data = json.dumps(value).encode() + self.send_response(200) + self.send_header("content-type", "application/json") + self.send_header("content-length", str(len(data))) + self.end_headers() + self.wfile.write(data) + + +server = ThreadingHTTPServer(("127.0.0.1", 0), Handler) +print(server.server_address[1], flush=True) +server.serve_forever() diff --git a/tests/standalone_local.rs b/tests/standalone_local.rs new file mode 100644 index 00000000..4991755b --- /dev/null +++ b/tests/standalone_local.rs @@ -0,0 +1,129 @@ +//! Standalone Rinx with its own local assistant runtime (ADR 0007), at the +//! process level: the packaged kernel starts on the first authorized request, +//! two mini apps share it with isolated request state, a restart resumes the +//! same peer, and exit stops only the runtime Rinx owns. +//! +//! Needs an `octos` kernel with UPCR-2026-034 (octos-org/octos#2555) as +//! `RINX_TEST_OCTOS_BIN` and python3 for the scripted model +//! (`tests/fixtures/mock_llm.py`); without the kernel it says so and passes. +#![cfg(feature = "octos-local")] + +use std::io::BufRead; +use std::path::PathBuf; +use std::sync::{Arc, Mutex}; +use std::time::Duration; + +use octosense_app_peers::octos_core::{Core, Options}; +use octosense_app_peers::*; + +struct Child(std::process::Child, u16); +impl Drop for Child { + fn drop(&mut self) { + let _ = self.0.kill(); + let _ = self.0.wait(); + } +} + +fn model() -> Child { + let script = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures/mock_llm.py"); + let mut child = std::process::Command::new("python3") + .arg(script) + .stdout(std::process::Stdio::piped()) + .spawn() + .unwrap(); + let mut line = String::new(); + std::io::BufReader::new(child.stdout.take().unwrap()).read_line(&mut line).unwrap(); + Child(child, line.trim().parse().unwrap()) +} + +fn spec(instance: &str) -> ContextSpec { + ContextSpec { + account: "@alice:example.org".into(), + instance: instance.into(), + services: OCTOS_SERVICES.iter().map(|s| s.to_string()).collect(), + } +} + +fn turn(ctx: &Arc, text: &str) -> Result { + let (tx, rx) = std::sync::mpsc::channel(); + let tx = Mutex::new(tx); + ctx.call(ContextOp::Turn { text: text.into() }, Arc::new(move |e| { let _ = tx.lock().unwrap().send(e); }))?; + loop { + match rx.recv_timeout(Duration::from_secs(90)).map_err(|_| "timed out".to_owned())? { + ContextEvent::Complete(r) => return r, + ContextEvent::Data(_) => {} + } + } +} + +fn kernel_processes(core_dir: &std::path::Path) -> usize { + let out = std::process::Command::new("pgrep").args(["-f", &core_dir.to_string_lossy()]).output().unwrap(); + String::from_utf8_lossy(&out.stdout).lines().count() +} + +#[test] +fn standalone_rinx_owns_one_local_runtime_and_stops_only_it() { + let Some(kernel) = std::env::var_os("RINX_TEST_OCTOS_BIN") else { + eprintln!("RINX_TEST_OCTOS_BIN is not set: skipping"); + return; + }; + let data = std::env::temp_dir().join(format!("rinx-standalone-local-{}", std::process::id())); + let _ = std::fs::remove_dir_all(&data); + // Rinx's own data root and the packaged kernel, set explicitly (never PATH). + unsafe { + std::env::set_var("RINX_DATA_DIR", &data); + std::env::set_var("RINX_OCTOS_BIN", &kernel); + } + let model = model(); + rinx::octos_service::write_local_provider("local", "mock-model", &format!("http://127.0.0.1:{}/v1", model.1), "").unwrap(); + let core_dir = rinx::octos_service::local_core_dir(); + assert!(core_dir.starts_with(&data), "the kernel root is Rinx-owned: {}", core_dir.display()); + + // Someone else's kernel on another core dir must survive Rinx's exit. + let other_dir = data.join("someone-else/.octos"); + std::fs::create_dir_all(other_dir.join("profiles")).unwrap(); + std::fs::copy(core_dir.join("profiles/_main.json"), other_dir.join("profiles/_main.json")).unwrap(); + let other = Core::new(Options::default().core_dir(&other_dir).program(&kernel)); + let _other_conn = other.connect().unwrap(); + + let service = rinx::octos_service::local_service().unwrap(); + assert_eq!(service.deployment(), Deployment::StandaloneLocal); + assert_eq!(service.settings_entry(), SettingsEntry::AppLocal); + assert_eq!(kernel_processes(&core_dir), 0, "nothing runs before the first request"); + service.set_account(Some("@alice:example.org")); + let notes = service.open_context(spec("dev.example.notes-g1")).unwrap(); + let poll = service.open_context(spec("dev.example.poll-g1")).unwrap(); + assert_eq!(turn(¬es, "notes question").unwrap()["text"], "ECHO: notes question"); + assert_eq!(turn(&poll, "poll question").unwrap()["text"], "ECHO: poll question"); + assert_eq!(kernel_processes(&core_dir), 1, "one runtime shared by both mini apps"); + // Isolated request state: separate context workspaces and memory namespaces. + let peers = core_dir.join("profiles/_main/data/peers"); + let peer = std::fs::read_dir(&peers).unwrap().flatten().next().unwrap().path(); + let contexts: Vec = std::fs::read_dir(&peer) + .unwrap() + .flatten() + .map(|e| e.file_name().to_string_lossy().into_owned()) + .filter(|n| n.starts_with("context-")) + .collect(); + assert_eq!(contexts.len(), 2, "{contexts:?}"); + assert_eq!(std::fs::read_to_string(peer.join("originator")).unwrap(), "_main:api:rinx#root"); + + // Exit: only Rinx's runtime stops. + service.shutdown(); + std::thread::sleep(Duration::from_secs(2)); + assert_eq!(kernel_processes(&core_dir), 0, "Rinx's runtime stopped"); + assert!(other.status().running, "another owner's kernel keeps running"); + assert_eq!(kernel_processes(&other_dir), 1); + + // Restart: the same peer resumes. + let service = rinx::octos_service::local_service().unwrap(); + service.set_account(Some("@alice:example.org")); + let again = service.open_context(spec("dev.example.notes-g2")).unwrap(); + assert_eq!(turn(&again, "after restart").unwrap()["text"], "ECHO: after restart"); + let peers_now: Vec<_> = std::fs::read_dir(&peers).unwrap().flatten().collect(); + assert_eq!(peers_now.len(), 1, "resumed, not re-created"); + service.shutdown(); + drop(_other_conn); + other.shutdown_within(Duration::from_secs(5)); + let _ = std::fs::remove_dir_all(&data); +} diff --git a/tests/standalone_remote.rs b/tests/standalone_remote.rs new file mode 100644 index 00000000..b1e57114 --- /dev/null +++ b/tests/standalone_remote.rs @@ -0,0 +1,154 @@ +//! Standalone Rinx with an explicit remote octos server (ADR 0007), against +//! a real `octos serve` started here with a fixture bearer token: an +//! authenticated connection and a server-provisioned scoped workspace work; +//! a wrong token is refused; an account change and a server/profile +//! replacement drop late replies; Rinx's exit leaves the server running. +//! +//! Needs `RINX_TEST_OCTOS_BIN` (octos with UPCR-2026-034) and python3; without +//! the kernel it says so and passes. No real credentials: the token is a +//! fixture and the model is `tests/fixtures/mock_llm.py`. +#![cfg(feature = "octos-remote")] + +use std::io::BufRead; +use std::path::PathBuf; +use std::sync::{Arc, Mutex}; +use std::time::Duration; + +use octosense_app_peers::*; + +struct Proc(std::process::Child); +impl Drop for Proc { + fn drop(&mut self) { + let _ = self.0.kill(); + let _ = self.0.wait(); + } +} + +fn model() -> (Proc, u16) { + let script = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures/mock_llm.py"); + let mut child = std::process::Command::new("python3") + .arg(script) + .stdout(std::process::Stdio::piped()) + .spawn() + .unwrap(); + let mut line = String::new(); + std::io::BufReader::new(child.stdout.take().unwrap()).read_line(&mut line).unwrap(); + let port = line.trim().parse().unwrap(); + (Proc(child), port) +} + +fn free_port() -> u16 { + std::net::TcpListener::bind("127.0.0.1:0").unwrap().local_addr().unwrap().port() +} + +fn server_alive(port: u16) -> bool { + std::net::TcpStream::connect(("127.0.0.1", port)).is_ok() +} + +fn spec(account: &str, instance: &str) -> ContextSpec { + ContextSpec { + account: account.into(), + instance: instance.into(), + services: OCTOS_SERVICES.iter().map(|s| s.to_string()).collect(), + } +} + +fn call(ctx: &Arc, op: ContextOp) -> std::sync::mpsc::Receiver { + let (tx, rx) = std::sync::mpsc::channel(); + let tx = Mutex::new(tx); + ctx.call(op, Arc::new(move |e| { let _ = tx.lock().unwrap().send(e); })).unwrap(); + rx +} + +fn complete(rx: &std::sync::mpsc::Receiver, wait: Duration) -> Option> { + let deadline = std::time::Instant::now() + wait; + loop { + match rx.recv_timeout(deadline.saturating_duration_since(std::time::Instant::now())) { + Ok(ContextEvent::Complete(r)) => return Some(r), + Ok(ContextEvent::Data(_)) => {} + Err(_) => return None, + } + } +} + +#[test] +fn standalone_rinx_uses_an_explicit_authenticated_remote_server() { + let Some(kernel) = std::env::var_os("RINX_TEST_OCTOS_BIN") else { + eprintln!("RINX_TEST_OCTOS_BIN is not set: skipping"); + return; + }; + let dir = std::env::temp_dir().join(format!("rinx-standalone-remote-{}", std::process::id())); + let _ = std::fs::remove_dir_all(&dir); + let server_dir = dir.join("server"); + let rinx_dir = dir.join("rinx"); + std::fs::create_dir_all(server_dir.join("profiles")).unwrap(); + unsafe { std::env::set_var("RINX_DATA_DIR", &rinx_dir) }; + let (_model, model_port) = model(); + std::fs::write( + server_dir.join("profiles/_main.json"), + serde_json::json!({ + "id": "_main", "name": "Main", "enabled": true, + "created_at": "2026-09-27T00:00:00Z", "updated_at": "2026-09-27T00:00:00Z", + "config": {"llm": {"primary": {"family_id": "local", "model_id": "mock-model", + "route": {"base_url": format!("http://127.0.0.1:{model_port}/v1"), "api_type": "openai"}}}} + }) + .to_string(), + ) + .unwrap(); + let port = free_port(); + let token = "rinx-test-fixture-token"; + let _server = Proc( + std::process::Command::new(&kernel) + .args(["serve", "--port", &port.to_string(), "--auth-token", token, "--data-dir"]) + .arg(&server_dir) + .env("OCTOS_HOME", &server_dir) + .stdout(std::process::Stdio::null()) + .stderr(std::process::Stdio::null()) + .spawn() + .unwrap(), + ); + for _ in 0..100 { + if server_alive(port) { + break; + } + std::thread::sleep(Duration::from_millis(100)); + } + let url = format!("http://127.0.0.1:{port}"); + + // A wrong token is refused; nothing runs. + rinx::octos_service::use_remote(&url, "_main", "not-the-token").unwrap(); + let service = rinx::octos_service::service().unwrap(); + service.set_account(Some("@alice:example.org")); + let ctx = service.open_context(spec("@alice:example.org", "notes-g1")).unwrap(); + let refused = complete(&call(&ctx, ContextOp::Open), Duration::from_secs(20)).expect("an answer"); + assert!(refused.is_err(), "{refused:?}"); + + // The right token: an authenticated connection and a scoped workspace. + rinx::octos_service::use_remote(&url, "_main", token).unwrap(); + let service = rinx::octos_service::service().unwrap(); + assert_eq!(service.deployment(), Deployment::StandaloneRemote); + assert!(!ctx.is_open(), "replacing the server revoked the old contexts"); + service.set_account(Some("@alice:example.org")); + let ctx = service.open_context(spec("@alice:example.org", "notes-g2")).unwrap(); + let answer = complete(&call(&ctx, ContextOp::Turn { text: "remote question".into() }), Duration::from_secs(90)) + .unwrap() + .unwrap(); + assert_eq!(answer["text"], "ECHO: remote question"); + let workspaces = server_dir.join("profiles/_main/data/app-workspaces/app/rinx"); + assert!(workspaces.is_dir(), "the server provisioned the workspace: {}", workspaces.display()); + assert!(!rinx_dir.join("octos/.octos").exists(), "no local runtime in remote mode"); + let saved = std::fs::read_to_string(rinx_dir.join("octos/assistant.json")).unwrap(); + assert!(!saved.contains(token), "the token is never written to disk"); + + // An account change drops the late reply of the previous account. + let slow = call(&ctx, ContextOp::Turn { text: "SLOW private".into() }); + std::thread::sleep(Duration::from_secs(2)); + service.set_account(Some("@bob:example.org")); + assert!(complete(&slow, Duration::from_secs(25)).is_none(), "a stale reply reached the next account"); + + // Exit leaves the server running. + rinx::octos_service::shutdown(); + std::thread::sleep(Duration::from_secs(1)); + assert!(server_alive(port), "Rinx's exit must not stop the server"); + let _ = std::fs::remove_dir_all(&dir); +} From 4cad3a5e39fcbe4532f68347f1821bf3ab07d05a Mon Sep 17 00:00:00 2001 From: ymote <151983+ymote@users.noreply.github.com> Date: Sat, 26 Sep 2026 20:29:00 -0700 Subject: [PATCH 07/10] Rinx on the current runtime; keep the kernel's host token per peer makepad db4691d0 (makepad#35) and OctoScript-Makepad c3d53ba8 (#46) carry the Splash reapply_text and stateful-input support the mini-app host uses on the current runtime (d0a9def5 / 99c1e5ee), so OctoSense shells can link Rinx at their pins. octosense-app-peers 4fa0f122 carries the kernel's host token (octos UPCR-2026-034 review); Rinx keeps it under octos/peers (0600) so a restart resumes its peer. Co-Authored-By: Claude Opus 5.5 (1M context) --- Cargo.lock | 314 ++++++++++---------- Cargo.toml | 84 +++--- crates/article-core/Cargo.toml | 2 +- docs/adr/0007-host-owned-octos-app-peers.md | 18 +- src/octos_service.rs | 14 +- 5 files changed, 224 insertions(+), 208 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1cb0ca07..9051b8cf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5,7 +5,7 @@ version = 4 [[package]] name = "ab_glyph_rasterizer" version = "0.1.8" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" [[package]] name = "accessory" @@ -381,7 +381,7 @@ checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" [[package]] name = "arrayvec" version = "0.7.6" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" [[package]] name = "arrayvec" @@ -434,7 +434,7 @@ checksum = "d92bec98840b8f03a5ff5413de5293bfcd8bf96467cf5452609f939ec6f5de16" [[package]] name = "ash" version = "0.38.0+1.3.281" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" dependencies = [ "libloading 0.8.9", ] @@ -947,9 +947,9 @@ dependencies = [ [[package]] name = "bit-set" version = "0.8.0" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" dependencies = [ - "bit-vec 0.8.0 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", + "bit-vec 0.8.0 (git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f)", ] [[package]] @@ -961,7 +961,7 @@ checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" [[package]] name = "bit-vec" version = "0.8.0" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" [[package]] name = "bitflags" @@ -972,7 +972,7 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" version = "2.10.0" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" [[package]] name = "bitflags" @@ -1234,7 +1234,7 @@ checksum = "175812e0be2bccb6abe50bb8d566126198344f707e304f45c648fd8f2cc0365e" [[package]] name = "bytemuck" version = "1.25.0" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" [[package]] name = "bytemuck" @@ -1265,7 +1265,7 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "byteorder" version = "1.5.0" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" [[package]] name = "byteorder-lite" @@ -1376,7 +1376,7 @@ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "cfg-if" version = "1.0.4" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" [[package]] name = "cfg_aliases" @@ -1387,7 +1387,7 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "cfg_aliases" version = "0.2.1" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" [[package]] name = "chacha20" @@ -1995,7 +1995,7 @@ checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" [[package]] name = "crunchy" version = "0.2.4" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" [[package]] name = "crypto-bigint" @@ -2606,7 +2606,7 @@ checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" [[package]] name = "downcast-rs" version = "1.2.1" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" [[package]] name = "dtoa" @@ -2859,7 +2859,7 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "equivalent" version = "1.0.2" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" [[package]] name = "errno" @@ -3159,7 +3159,7 @@ checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" [[package]] name = "foldhash" version = "0.2.0" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" [[package]] name = "font-types" @@ -3417,9 +3417,9 @@ dependencies = [ [[package]] name = "fxhash" version = "0.2.1" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" dependencies = [ - "byteorder 1.5.0 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", + "byteorder 1.5.0 (git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f)", ] [[package]] @@ -4460,9 +4460,9 @@ dependencies = [ [[package]] name = "hashbrown" version = "0.16.1" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" dependencies = [ - "foldhash 0.2.0 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", + "foldhash 0.2.0 (git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f)", ] [[package]] @@ -4523,7 +4523,7 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "hexf-parse" version = "0.2.1" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" [[package]] name = "hilog-sys" @@ -5138,10 +5138,10 @@ dependencies = [ [[package]] name = "indexmap" version = "2.13.0" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" dependencies = [ - "equivalent 1.0.2 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", - "hashbrown 0.16.1 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", + "equivalent 1.0.2 (git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f)", + "hashbrown 0.16.1 (git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f)", ] [[package]] @@ -5606,10 +5606,10 @@ dependencies = [ [[package]] name = "libloading" version = "0.8.9" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" dependencies = [ - "cfg-if 1.0.4 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", - "windows-link 0.2.1 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", + "cfg-if 1.0.4 (git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f)", + "windows-link 0.2.1 (git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f)", ] [[package]] @@ -5844,7 +5844,7 @@ dependencies = [ [[package]] name = "makepad-ai-services" version = "0.1.0" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" dependencies = [ "makepad-micro-serde", "makepad-platform", @@ -5863,7 +5863,7 @@ dependencies = [ [[package]] name = "makepad-app-module" version = "0.1.0" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" dependencies = [ "makepad-ai-services", "makepad-strict-json", @@ -5873,7 +5873,7 @@ dependencies = [ [[package]] name = "makepad-apple-sys" version = "1.0.0" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" dependencies = [ "makepad-objc-sys", ] @@ -5881,12 +5881,12 @@ dependencies = [ [[package]] name = "makepad-byteorder-lite" version = "0.1.0" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" [[package]] name = "makepad-code-editor" version = "2.0.0" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" dependencies = [ "makepad-widgets", ] @@ -5894,7 +5894,7 @@ dependencies = [ [[package]] name = "makepad-derive-wasm-bridge" version = "1.0.0" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" dependencies = [ "makepad-micro-proc-macro", ] @@ -5902,7 +5902,7 @@ dependencies = [ [[package]] name = "makepad-derive-widget" version = "2.0.0" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" dependencies = [ "makepad-live-id", "makepad-micro-proc-macro", @@ -5911,7 +5911,7 @@ dependencies = [ [[package]] name = "makepad-draw" version = "2.0.0" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" dependencies = [ "ab_glyph_rasterizer", "fxhash", @@ -5929,7 +5929,7 @@ dependencies = [ "sdfer", "serde", "ttf-parser 0.24.1", - "unicode-bidi 0.3.18 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", + "unicode-bidi 0.3.18 (git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f)", "unicode-linebreak", "unicode-segmentation 1.12.0", ] @@ -5937,7 +5937,7 @@ dependencies = [ [[package]] name = "makepad-error-log" version = "1.0.0" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" dependencies = [ "makepad-micro-serde", ] @@ -5945,12 +5945,12 @@ dependencies = [ [[package]] name = "makepad-fast-inflate" version = "0.1.0" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" [[package]] name = "makepad-filesystem-watcher" version = "0.1.0" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" dependencies = [ "makepad-git", ] @@ -5958,25 +5958,25 @@ dependencies = [ [[package]] name = "makepad-futures" version = "1.0.0" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" [[package]] name = "makepad-futures-legacy" version = "1.0.0" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" [[package]] name = "makepad-gif" version = "0.1.0" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" dependencies = [ - "weezl 0.1.12 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", + "weezl 0.1.12 (git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f)", ] [[package]] name = "makepad-git" version = "0.1.0" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" dependencies = [ "makepad-fast-inflate", ] @@ -5984,10 +5984,10 @@ dependencies = [ [[package]] name = "makepad-half" version = "2.7.1" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" dependencies = [ - "cfg-if 1.0.4 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", - "crunchy 0.2.4 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", + "cfg-if 1.0.4 (git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f)", + "crunchy 0.2.4 (git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f)", "num-traits 0.2.20", "zerocopy 0.8.39", ] @@ -6013,7 +6013,7 @@ dependencies = [ [[package]] name = "makepad-html" version = "1.0.0" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" dependencies = [ "makepad-live-id", ] @@ -6027,7 +6027,7 @@ checksum = "9775cbec5fa0647500c3e5de7c850280a88335d1d2d770e5aa2332b801ba7064" [[package]] name = "makepad-latex-math" version = "0.1.0" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" dependencies = [ "ttf-parser 0.24.1", ] @@ -6035,7 +6035,7 @@ dependencies = [ [[package]] name = "makepad-live-id" version = "1.0.0" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" dependencies = [ "makepad-live-id-macros", "serde", @@ -6044,7 +6044,7 @@ dependencies = [ [[package]] name = "makepad-live-id-macros" version = "1.0.0" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" dependencies = [ "makepad-micro-proc-macro", ] @@ -6052,7 +6052,7 @@ dependencies = [ [[package]] name = "makepad-live-reload-core" version = "0.1.0" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" dependencies = [ "makepad-filesystem-watcher", ] @@ -6060,7 +6060,7 @@ dependencies = [ [[package]] name = "makepad-markdown" version = "0.1.0" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" dependencies = [ "blake3", "comrak", @@ -6074,7 +6074,7 @@ dependencies = [ [[package]] name = "makepad-markdown-widgets" version = "0.1.0" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" dependencies = [ "blake3", "core-foundation 0.10.1", @@ -6094,7 +6094,7 @@ dependencies = [ [[package]] name = "makepad-math" version = "1.0.0" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" dependencies = [ "makepad-micro-serde", ] @@ -6102,12 +6102,12 @@ dependencies = [ [[package]] name = "makepad-micro-proc-macro" version = "1.0.0" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" [[package]] name = "makepad-micro-serde" version = "1.0.0" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" dependencies = [ "makepad-live-id", "makepad-micro-serde-derive", @@ -6116,7 +6116,7 @@ dependencies = [ [[package]] name = "makepad-micro-serde-derive" version = "1.0.0" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" dependencies = [ "makepad-micro-proc-macro", ] @@ -6124,7 +6124,7 @@ dependencies = [ [[package]] name = "makepad-network" version = "1.0.0" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" dependencies = [ "makepad-apple-sys", "makepad-error-log", @@ -6132,18 +6132,18 @@ dependencies = [ "makepad-live-id", "makepad-micro-serde", "makepad-script", - "windows 0.62.2 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", + "windows 0.62.2 (git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f)", ] [[package]] name = "makepad-objc-sys" version = "1.0.0" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" [[package]] name = "makepad-platform" version = "2.0.0" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" dependencies = [ "ash", "bitflags 2.10.0", @@ -6169,34 +6169,34 @@ dependencies = [ "napi-ohos", "ohos-sys", "rqrr", - "smallvec 1.15.1 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", + "smallvec 1.15.1 (git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f)", "wayland-client", "wayland-egl", "wayland-protocols", - "windows 0.62.2 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", - "windows-core 0.62.2 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", + "windows 0.62.2 (git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f)", + "windows-core 0.62.2 (git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f)", "windows-targets 0.52.6", ] [[package]] name = "makepad-platform-video" version = "1.0.0" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" dependencies = [ "makepad-apple-sys", "makepad-objc-sys", - "windows 0.62.2 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", + "windows 0.62.2 (git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f)", ] [[package]] name = "makepad-regex" version = "0.1.0" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" [[package]] name = "makepad-script" version = "1.0.0" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" dependencies = [ "makepad-error-log", "makepad-html 1.0.0", @@ -6205,13 +6205,13 @@ dependencies = [ "makepad-regex", "makepad-script-derive", "makepad-stitch", - "smallvec 1.15.1 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", + "smallvec 1.15.1 (git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f)", ] [[package]] name = "makepad-script-derive" version = "1.0.0" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" dependencies = [ "makepad-micro-proc-macro", ] @@ -6219,7 +6219,7 @@ dependencies = [ [[package]] name = "makepad-script-std" version = "1.0.0" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" dependencies = [ "makepad-network", "makepad-script", @@ -6228,22 +6228,22 @@ dependencies = [ [[package]] name = "makepad-shared-bytes" version = "1.0.0" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" [[package]] name = "makepad-stitch" version = "0.1.0" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" [[package]] name = "makepad-strict-json" version = "0.1.0" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" [[package]] name = "makepad-studio-protocol" version = "0.1.0" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" dependencies = [ "bitflags 2.10.0", "makepad-error-log", @@ -6255,7 +6255,7 @@ dependencies = [ [[package]] name = "makepad-svg" version = "1.0.0" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" dependencies = [ "makepad-html 1.0.0", "makepad-live-id", @@ -6264,7 +6264,7 @@ dependencies = [ [[package]] name = "makepad-tsdf" version = "0.1.0" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" dependencies = [ "makepad-math", "makepad-micro-serde", @@ -6273,7 +6273,7 @@ dependencies = [ [[package]] name = "makepad-wasm-bridge" version = "1.0.0" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" dependencies = [ "makepad-derive-wasm-bridge", "makepad-live-id", @@ -6282,7 +6282,7 @@ dependencies = [ [[package]] name = "makepad-webp" version = "0.2.4" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" dependencies = [ "makepad-byteorder-lite", ] @@ -6290,7 +6290,7 @@ dependencies = [ [[package]] name = "makepad-widgets" version = "2.0.0" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" dependencies = [ "makepad-derive-widget", "makepad-draw", @@ -6307,7 +6307,7 @@ dependencies = [ [[package]] name = "makepad-zune-bmp" version = "0.5.2" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" dependencies = [ "makepad-error-log", "makepad-zune-core", @@ -6316,7 +6316,7 @@ dependencies = [ [[package]] name = "makepad-zune-core" version = "0.5.1" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" dependencies = [ "makepad-error-log", ] @@ -6324,7 +6324,7 @@ dependencies = [ [[package]] name = "makepad-zune-inflate" version = "0.2.54" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" dependencies = [ "simd-adler32 0.3.9", ] @@ -6332,7 +6332,7 @@ dependencies = [ [[package]] name = "makepad-zune-jpeg" version = "0.5.15" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" dependencies = [ "makepad-zune-core", ] @@ -6340,7 +6340,7 @@ dependencies = [ [[package]] name = "makepad-zune-png" version = "0.5.2" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" dependencies = [ "makepad-fast-inflate", "makepad-zune-core", @@ -6350,7 +6350,7 @@ dependencies = [ [[package]] name = "makepad-zune-qoi" version = "0.5.2" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" dependencies = [ "makepad-zune-core", ] @@ -6812,7 +6812,7 @@ checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "memchr" version = "2.7.6" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" [[package]] name = "memmap2" @@ -7002,14 +7002,14 @@ dependencies = [ [[package]] name = "naga" version = "27.0.3" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" dependencies = [ "arrayvec 0.7.6", - "bit-set 0.8.0 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", + "bit-set 0.8.0 (git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f)", "bitflags 2.10.0", - "cfg-if 1.0.4 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", - "cfg_aliases 0.2.1 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", - "hashbrown 0.16.1 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", + "cfg-if 1.0.4 (git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f)", + "cfg_aliases 0.2.1 (git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f)", + "hashbrown 0.16.1 (git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f)", "hexf-parse", "indexmap 2.13.0", "makepad-error-log", @@ -7269,7 +7269,7 @@ dependencies = [ [[package]] name = "num-traits" version = "0.2.20" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" [[package]] name = "num_cpus" @@ -7865,7 +7865,7 @@ dependencies = [ [[package]] name = "octoscript-makepad" version = "0.1.0" -source = "git+https://www.github.com/OctoSense-org/Octoscript-Makepad.git?rev=b9034566b0607c5bb8c04134d17139f99989e1d0#b9034566b0607c5bb8c04134d17139f99989e1d0" +source = "git+https://www.github.com/OctoSense-org/Octoscript-Makepad.git?rev=c3d53ba8bdbc219478b98b34fc73066228d9dfb3#c3d53ba8bdbc219478b98b34fc73066228d9dfb3" dependencies = [ "octoscript-render", "octoscript-ui-l0", @@ -7875,12 +7875,12 @@ dependencies = [ [[package]] name = "octoscript-node" version = "0.1.0" -source = "git+https://www.github.com/OctoSense-org/Octoscript-Makepad.git?rev=b9034566b0607c5bb8c04134d17139f99989e1d0#b9034566b0607c5bb8c04134d17139f99989e1d0" +source = "git+https://www.github.com/OctoSense-org/Octoscript-Makepad.git?rev=c3d53ba8bdbc219478b98b34fc73066228d9dfb3#c3d53ba8bdbc219478b98b34fc73066228d9dfb3" [[package]] name = "octoscript-render" version = "0.1.0" -source = "git+https://www.github.com/OctoSense-org/Octoscript-Makepad.git?rev=b9034566b0607c5bb8c04134d17139f99989e1d0#b9034566b0607c5bb8c04134d17139f99989e1d0" +source = "git+https://www.github.com/OctoSense-org/Octoscript-Makepad.git?rev=c3d53ba8bdbc219478b98b34fc73066228d9dfb3#c3d53ba8bdbc219478b98b34fc73066228d9dfb3" dependencies = [ "makepad-script", "octoscript-node", @@ -7899,7 +7899,7 @@ dependencies = [ [[package]] name = "octoscript-widgets" version = "0.1.0" -source = "git+https://www.github.com/OctoSense-org/Octoscript-Makepad.git?rev=b9034566b0607c5bb8c04134d17139f99989e1d0#b9034566b0607c5bb8c04134d17139f99989e1d0" +source = "git+https://www.github.com/OctoSense-org/Octoscript-Makepad.git?rev=c3d53ba8bdbc219478b98b34fc73066228d9dfb3#c3d53ba8bdbc219478b98b34fc73066228d9dfb3" dependencies = [ "makepad-widgets", "serde_json", @@ -7908,7 +7908,7 @@ dependencies = [ [[package]] name = "octosense-app-peers" version = "0.1.0" -source = "git+https://github.com/OctoSense-org/OctoSense-System-Apps.git?rev=64aa865e306a1411a3f020903ddb7ac922aa30ae#64aa865e306a1411a3f020903ddb7ac922aa30ae" +source = "git+https://github.com/OctoSense-org/OctoSense-System-Apps.git?rev=4fa0f122ab01d58e468d339f1920ec2758741012#4fa0f122ab01d58e468d339f1920ec2758741012" dependencies = [ "futures-util", "log", @@ -7934,7 +7934,7 @@ dependencies = [ [[package]] name = "octosense-llm-config" version = "0.1.0" -source = "git+https://github.com/OctoSense-org/OctoSense-System-Apps.git?rev=64aa865e306a1411a3f020903ddb7ac922aa30ae#64aa865e306a1411a3f020903ddb7ac922aa30ae" +source = "git+https://github.com/OctoSense-org/OctoSense-System-Apps.git?rev=4fa0f122ab01d58e468d339f1920ec2758741012#4fa0f122ab01d58e468d339f1920ec2758741012" dependencies = [ "argon2", "chacha20poly1305 0.10.1", @@ -7950,7 +7950,7 @@ dependencies = [ [[package]] name = "octosense-octos-core" version = "0.1.0" -source = "git+https://github.com/OctoSense-org/OctoSense-System-Apps.git?rev=64aa865e306a1411a3f020903ddb7ac922aa30ae#64aa865e306a1411a3f020903ddb7ac922aa30ae" +source = "git+https://github.com/OctoSense-org/OctoSense-System-Apps.git?rev=4fa0f122ab01d58e468d339f1920ec2758741012#4fa0f122ab01d58e468d339f1920ec2758741012" dependencies = [ "log", "octos-cli", @@ -7969,7 +7969,7 @@ checksum = "8d380ab6c951261a0e44306245bc960b3b3367f099a7da7156bd1a3cacaf783c" [[package]] name = "once_cell" version = "1.21.3" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" [[package]] name = "once_cell" @@ -8447,7 +8447,7 @@ checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" [[package]] name = "pkg-config" version = "0.3.32" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" [[package]] name = "plain" @@ -8687,10 +8687,10 @@ dependencies = [ [[package]] name = "pulldown-cmark" version = "0.12.2" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" dependencies = [ "bitflags 2.10.0", - "memchr 2.7.6 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", + "memchr 2.7.6 (git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f)", "unicase 2.9.0", ] @@ -9828,7 +9828,7 @@ checksum = "b74b56ffa8bb2830709a538c2cbcae9aa062db0d2a42563bfb09bdaae44020eb" [[package]] name = "rustc-hash" version = "1.1.0" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" [[package]] name = "rustc-hash" @@ -9953,17 +9953,17 @@ checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "rustybuzz" version = "0.18.0" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" dependencies = [ "bitflags 2.10.0", "bytemuck 1.25.0", "makepad-error-log", - "smallvec 1.15.1 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", + "smallvec 1.15.1 (git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f)", "ttf-parser 0.24.1", "unicode-bidi-mirroring 0.3.0", "unicode-ccc 0.3.0", "unicode-properties 0.1.4", - "unicode-script 0.5.8 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", + "unicode-script 0.5.8 (git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f)", ] [[package]] @@ -10110,7 +10110,7 @@ checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" [[package]] name = "scoped-tls" version = "1.0.1" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" [[package]] name = "scopeguard" @@ -10141,7 +10141,7 @@ dependencies = [ [[package]] name = "sdfer" version = "0.2.1" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" [[package]] name = "sealed" @@ -10580,7 +10580,7 @@ dependencies = [ [[package]] name = "simd-adler32" version = "0.3.9" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" [[package]] name = "simd-adler32" @@ -10686,7 +10686,7 @@ dependencies = [ [[package]] name = "smallvec" version = "1.15.1" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" [[package]] name = "smol_str" @@ -10720,7 +10720,7 @@ dependencies = [ [[package]] name = "spirv" version = "0.3.0+sdk-1.3.268.0" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" dependencies = [ "bitflags 2.10.0", ] @@ -11435,7 +11435,7 @@ dependencies = [ [[package]] name = "thiserror" version = "2.0.18" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" dependencies = [ "thiserror-impl 2.0.18", ] @@ -11463,7 +11463,7 @@ dependencies = [ [[package]] name = "thiserror-impl" version = "2.0.18" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" dependencies = [ "makepad-micro-proc-macro", ] @@ -12102,7 +12102,7 @@ dependencies = [ [[package]] name = "ttf-parser" version = "0.24.1" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" [[package]] name = "ttf-parser" @@ -12257,7 +12257,7 @@ checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" [[package]] name = "unicase" version = "2.9.0" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" [[package]] name = "unicode-bidi" @@ -12268,12 +12268,12 @@ checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" [[package]] name = "unicode-bidi" version = "0.3.18" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" [[package]] name = "unicode-bidi-mirroring" version = "0.3.0" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" [[package]] name = "unicode-bidi-mirroring" @@ -12290,7 +12290,7 @@ checksum = "7eec5d1121208364f6793f7d2e222bf75a915c19557537745b195b253dd64217" [[package]] name = "unicode-ccc" version = "0.3.0" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" [[package]] name = "unicode-ccc" @@ -12307,12 +12307,12 @@ checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" [[package]] name = "unicode-ident" version = "1.0.22" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" [[package]] name = "unicode-linebreak" version = "0.1.5" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" [[package]] name = "unicode-normalization" @@ -12332,7 +12332,7 @@ checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" [[package]] name = "unicode-properties" version = "0.1.4" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" [[package]] name = "unicode-script" @@ -12343,12 +12343,12 @@ checksum = "383ad40bb927465ec0ce7720e033cb4ca06912855fc35db31b5755d0de75b1ee" [[package]] name = "unicode-script" version = "0.5.8" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" [[package]] name = "unicode-segmentation" version = "1.12.0" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" [[package]] name = "unicode-segmentation" @@ -12722,10 +12722,10 @@ dependencies = [ [[package]] name = "wayland-backend" version = "0.3.12" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" dependencies = [ "downcast-rs", - "scoped-tls 1.0.1 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", + "scoped-tls 1.0.1 (git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f)", "smallvec 1.15.1 (registry+https://github.com/rust-lang/crates.io-index)", "wayland-sys", ] @@ -12733,7 +12733,7 @@ dependencies = [ [[package]] name = "wayland-client" version = "0.31.12" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" dependencies = [ "bitflags 2.10.0", "wayland-backend", @@ -12743,7 +12743,7 @@ dependencies = [ [[package]] name = "wayland-egl" version = "0.32.9" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" dependencies = [ "wayland-backend", "wayland-sys", @@ -12752,7 +12752,7 @@ dependencies = [ [[package]] name = "wayland-protocols" version = "0.32.10" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" dependencies = [ "bitflags 2.10.0", "wayland-backend", @@ -12762,10 +12762,10 @@ dependencies = [ [[package]] name = "wayland-sys" version = "0.31.8" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" dependencies = [ "makepad-error-log", - "pkg-config 0.3.32 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", + "pkg-config 0.3.32 (git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f)", ] [[package]] @@ -12856,7 +12856,7 @@ checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88" [[package]] name = "weezl" version = "0.1.12" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" [[package]] name = "which" @@ -12989,11 +12989,11 @@ dependencies = [ [[package]] name = "windows" version = "0.62.2" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" dependencies = [ - "windows-collections 0.3.2 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", - "windows-core 0.62.2 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", - "windows-future 0.3.2 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", + "windows-collections 0.3.2 (git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f)", + "windows-core 0.62.2 (git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f)", + "windows-future 0.3.2 (git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f)", ] [[package]] @@ -13017,9 +13017,9 @@ dependencies = [ [[package]] name = "windows-collections" version = "0.3.2" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" dependencies = [ - "windows-core 0.62.2 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", + "windows-core 0.62.2 (git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f)", ] [[package]] @@ -13063,11 +13063,11 @@ dependencies = [ [[package]] name = "windows-core" version = "0.62.2" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" dependencies = [ - "windows-link 0.2.1 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", - "windows-result 0.4.1 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", - "windows-strings 0.5.1 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", + "windows-link 0.2.1 (git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f)", + "windows-result 0.4.1 (git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f)", + "windows-strings 0.5.1 (git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f)", ] [[package]] @@ -13095,9 +13095,9 @@ dependencies = [ [[package]] name = "windows-future" version = "0.3.2" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" dependencies = [ - "windows-core 0.62.2 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", + "windows-core 0.62.2 (git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f)", ] [[package]] @@ -13159,7 +13159,7 @@ checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] name = "windows-link" version = "0.2.1" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" [[package]] name = "windows-numerics" @@ -13233,9 +13233,9 @@ dependencies = [ [[package]] name = "windows-result" version = "0.4.1" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" dependencies = [ - "windows-link 0.2.1 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", + "windows-link 0.2.1 (git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f)", ] [[package]] @@ -13259,9 +13259,9 @@ dependencies = [ [[package]] name = "windows-strings" version = "0.5.1" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" dependencies = [ - "windows-link 0.2.1 (git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d)", + "windows-link 0.2.1 (git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f)", ] [[package]] @@ -13851,7 +13851,7 @@ dependencies = [ [[package]] name = "zerocopy" version = "0.8.39" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" [[package]] name = "zerocopy-derive" @@ -14081,29 +14081,29 @@ dependencies = [ [[patch.unused]] name = "makepad-ai" version = "1.0.0" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" [[patch.unused]] name = "makepad-aichat" version = "0.1.0" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" [[patch.unused]] name = "makepad-photos" version = "0.1.0" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" [[patch.unused]] name = "makepad-sheets" version = "0.1.0" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" [[patch.unused]] name = "makepad-wm-api" version = "0.1.0" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" [[patch.unused]] name = "makepad-wm-theme" version = "0.1.0" -source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://www.github.com/OctoSense-org/makepad.git?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" diff --git a/Cargo.toml b/Cargo.toml index a9d75847..290387c7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,15 +20,15 @@ uuid = { version = "1", features = ["v4"] } ## The assistant (ADR 0007): the scoped service contract a host injects. The ## local-runtime and remote connectors are optional (`octos-local`, ## `octos-remote`), so a hosted build links no runtime of its own. -octosense-app-peers = { git = "https://github.com/OctoSense-org/OctoSense-System-Apps.git", rev = "64aa865e306a1411a3f020903ddb7ac922aa30ae" } +octosense-app-peers = { git = "https://github.com/OctoSense-org/OctoSense-System-Apps.git", rev = "4fa0f122ab01d58e468d339f1920ec2758741012" } octoscript-ui-l0 = { git = "https://github.com/OctoSense-org/Octoscript.git", rev = "68f6a9df55692b5d8ef8873a12721e279a3f40d6" } -octoscript-makepad = { git = "https://github.com/OctoSense-org/Octoscript-Makepad.git", rev = "b9034566b0607c5bb8c04134d17139f99989e1d0" } -octoscript-widgets = { git = "https://github.com/OctoSense-org/Octoscript-Makepad.git", rev = "b9034566b0607c5bb8c04134d17139f99989e1d0" } +octoscript-makepad = { git = "https://github.com/OctoSense-org/Octoscript-Makepad.git", rev = "c3d53ba8bdbc219478b98b34fc73066228d9dfb3" } +octoscript-widgets = { git = "https://github.com/OctoSense-org/Octoscript-Makepad.git", rev = "c3d53ba8bdbc219478b98b34fc73066228d9dfb3" } octosense-app-policy = { git = "https://github.com/OctoSense-org/OctoSense-App-Hub.git", rev = "46d67e51b62827a1224b1aacddc2a7b9e69185fc", features = ["splash"] } article-makepad = { path = "crates/article-makepad" } ## The OctoSense module contract. Only a host build uses it, and the host redirects ## all of makepad to its own copy (OctoSense-org/makepad rinx/octosense-module-windows). -makepad-app-module = { git = "https://github.com/OctoSense-org/makepad", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d", optional = true } +makepad-app-module = { git = "https://github.com/OctoSense-org/makepad", rev = "db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f", optional = true } makepad-html-renderer = { package = "makepad-html", git = "https://github.com/OctoSense-org/makepad-html", rev = "b16565ae1e56dd7c3a87f00455ae327df599ca3b", optional = true, features = ["makepad"] } # makepad-widgets = { git = "https://github.com/makepad/makepad", branch = "dev", features = ["serde"] } # makepad-code-editor = { git = "https://github.com/makepad/makepad", branch = "dev" } @@ -449,47 +449,47 @@ used_underscore_binding = "allow" # repository. OctoSense shells replace these with their prepared runtime source. [patch."https://github.com/OctoSense-org/makepad.git"] -makepad-script = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } -makepad-widgets = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } -makepad-code-editor = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } -makepad-app-module = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } -makepad-ai = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } -makepad-studio-protocol = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } -makepad-network = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } -makepad-wm-api = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } -makepad-ai-services = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } -makepad-strict-json = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } -makepad-wm-theme = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } -makepad-sheets = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } -makepad-photos = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } -makepad-aichat = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } -makepad-markdown = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } -makepad-markdown-widgets = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } +makepad-script = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" } +makepad-widgets = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" } +makepad-code-editor = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" } +makepad-app-module = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" } +makepad-ai = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" } +makepad-studio-protocol = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" } +makepad-network = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" } +makepad-wm-api = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" } +makepad-ai-services = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" } +makepad-strict-json = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" } +makepad-wm-theme = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" } +makepad-sheets = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" } +makepad-photos = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" } +makepad-aichat = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" } +makepad-markdown = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" } +makepad-markdown-widgets = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" } [patch."https://github.com/OctoSense-org/makepad"] -makepad-script = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } -makepad-widgets = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } -makepad-code-editor = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } -makepad-app-module = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } -makepad-ai = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } -makepad-studio-protocol = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } -makepad-network = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } -makepad-wm-api = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } -makepad-ai-services = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } -makepad-strict-json = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } -makepad-wm-theme = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } -makepad-sheets = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } -makepad-photos = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } -makepad-aichat = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } -makepad-markdown = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } -makepad-markdown-widgets = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } +makepad-script = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" } +makepad-widgets = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" } +makepad-code-editor = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" } +makepad-app-module = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" } +makepad-ai = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" } +makepad-studio-protocol = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" } +makepad-network = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" } +makepad-wm-api = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" } +makepad-ai-services = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" } +makepad-strict-json = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" } +makepad-wm-theme = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" } +makepad-sheets = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" } +makepad-photos = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" } +makepad-aichat = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" } +makepad-markdown = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" } +makepad-markdown-widgets = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" } [patch."https://github.com/kevinaboos/makepad"] -makepad-widgets = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } -makepad-code-editor = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } +makepad-widgets = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" } +makepad-code-editor = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" } [patch."https://github.com/ZhangHanDong/makepad.git"] -makepad-widgets = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d" } +makepad-widgets = { git = "https://www.github.com/OctoSense-org/makepad.git", rev = "db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" } [patch."https://github.com/OctoSense-org/Octoscript.git"] octoscript-ui-l0 = { git = "https://www.github.com/OctoSense-org/Octoscript.git", rev = "68f6a9df55692b5d8ef8873a12721e279a3f40d6" } @@ -498,6 +498,6 @@ octoscript-ui-l0 = { git = "https://www.github.com/OctoSense-org/Octoscript.git" octoscript-ui-l0 = { git = "https://www.github.com/OctoSense-org/Octoscript.git", rev = "68f6a9df55692b5d8ef8873a12721e279a3f40d6" } [patch."https://github.com/OctoSense-org/Octoscript-Makepad.git"] -octoscript-makepad = { git = "https://www.github.com/OctoSense-org/Octoscript-Makepad.git", rev = "b9034566b0607c5bb8c04134d17139f99989e1d0" } -octoscript-widgets = { git = "https://www.github.com/OctoSense-org/Octoscript-Makepad.git", rev = "b9034566b0607c5bb8c04134d17139f99989e1d0" } -octoscript-node = { git = "https://www.github.com/OctoSense-org/Octoscript-Makepad.git", rev = "b9034566b0607c5bb8c04134d17139f99989e1d0" } +octoscript-makepad = { git = "https://www.github.com/OctoSense-org/Octoscript-Makepad.git", rev = "c3d53ba8bdbc219478b98b34fc73066228d9dfb3" } +octoscript-widgets = { git = "https://www.github.com/OctoSense-org/Octoscript-Makepad.git", rev = "c3d53ba8bdbc219478b98b34fc73066228d9dfb3" } +octoscript-node = { git = "https://www.github.com/OctoSense-org/Octoscript-Makepad.git", rev = "c3d53ba8bdbc219478b98b34fc73066228d9dfb3" } diff --git a/crates/article-core/Cargo.toml b/crates/article-core/Cargo.toml index 74794610..beb7f34d 100644 --- a/crates/article-core/Cargo.toml +++ b/crates/article-core/Cargo.toml @@ -12,7 +12,7 @@ default = [] l0 = ["dep:octoscript-ui-l0"] [dependencies] -makepad-markdown = { git = "https://github.com/OctoSense-org/makepad", rev = "3fda5b6f9b48f390bd5396938a95d30ad035cd6d", features = ["editormd"] } +makepad-markdown = { git = "https://github.com/OctoSense-org/makepad", rev = "db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f", features = ["editormd"] } serde = { version = "1", features = ["derive"] } serde_json = "1" rand = "0.8.5" diff --git a/docs/adr/0007-host-owned-octos-app-peers.md b/docs/adr/0007-host-owned-octos-app-peers.md index f0355114..a7808987 100644 --- a/docs/adr/0007-host-owned-octos-app-peers.md +++ b/docs/adr/0007-host-owned-octos-app-peers.md @@ -427,9 +427,9 @@ listed for the owners' confirmation. | Layer | Repository and change | What it provides | | --- | --- | --- | -| Kernel | octos-org/octos#2555, UPCR-2026-034 | `peer/prepare` with `model` (parity with `peer_handoff`, effective model and fallback reported), `memory_namespace` (host-owned app peer bound to its workspace and an app/account memory namespace, system originator persisted), `resume` and a kernel-provisioned workspace for remote hosts. Adds `peer/model/set` (one peer's lane between turns, profile default untouched), `peer/context/open|close` (bound request contexts: kernel-minted sessions, child namespaces, refusal after close) and memory isolation for capture, retrieval, prompt injection, episodes and the refresh sweep | +| Kernel | octos-org/octos#2555, UPCR-2026-034 | Control of a host-owned app peer is bound to a host token minted at creation. Allocation is exclusive (no shared namespace or workspace), and torn bindings fail closed. `peer/prepare` with `model` (parity with `peer_handoff`, effective model and fallback reported), `memory_namespace` (host-owned app peer bound to its workspace and an app/account memory namespace, system originator persisted), `resume` and a kernel-provisioned workspace for remote hosts. Adds `peer/model/set` (one peer's lane between turns, profile default untouched), `peer/context/open|close` (bound request contexts: kernel-minted sessions, child namespaces, refusal after close) and memory isolation for capture, retrieval, prompt injection, episodes and the refresh sweep | | Capability contract | OctoSense-App-Hub#14 (`9e986135`, on main from `46d67e51`) | The exact `octos.*` and `matrix.*` service names, admitted by exact name, with store wording; history does not grant turns | -| Broker | OctoSense-System-Apps#14, #15 (`crates/app-peers`, `64aa865e`) | The contract Rinx consumes (`OctosAppService`, `OctosContext`), creation-time injection (`offer` / `claim` / `withdraw`) and the broker used for all three deployments. The broker makes one system-owned peer per app and account and one kernel request context per mini-app instance, checks the lease on every request and before every reply, and refuses a kernel without UPCR-2026-034. It runs over the shell kernel, an owned local kernel or a token-authenticated remote server | +| Broker | OctoSense-System-Apps#14, #15, #16 (`crates/app-peers`, `4fa0f122`) | The contract Rinx consumes (`OctosAppService`, `OctosContext`), creation-time injection (`offer` / `claim` / `withdraw`) and the broker used for all three deployments. The broker makes one system-owned peer per app and account and one kernel request context per mini-app instance, checks the lease on every request and before every reply, and refuses a kernel without UPCR-2026-034. It keeps each peer's host token (shell: `/../app-peers`; Rinx: `octos/peers`, mode 0600). It runs over the shell kernel, an owned local kernel or a token-authenticated remote server | | Rinx | this change | `src/octos_service.rs` selects the deployment: hosted from module creation, standalone local or remote from Rinx's assistant settings. `src/module.rs` declares the four `octos.*` services and claims the injected service. Mini apps get request contexts (`src/octoscript_apps/octos.rs`); admission and dispatch use exact names. Account changes revoke; hosted close releases; standalone exit stops only an owned runtime. The `octos-local` / `octos-remote` features keep the runtime out of `octosense-module` builds | `KernelProvider::shared` and the AppCard connection discovery are gone. No mode @@ -449,13 +449,19 @@ to OctoSense's Settings → Accounts → AI providers. - **Model selection.** Host policy may set a configured lane for an app's peer (`BrokerConfig::model_lane`, `peer/model/set`). No app-facing API selects a model or provider. -- **Remote credentials.** The standalone remote token stays in memory and is asked - for again after a restart. Only the URL and profile are persisted. The - connector authenticates by token only. +- **Remote credentials.** The standalone remote server token stays in memory and is + asked for again after a restart. Only the URL and profile are persisted. The + connector authenticates by token only. The kernel's per-peer host token is a + capability for Rinx's own peer, not a server login. It is kept in a 0600 file + so a restart resumes the peer. +- **Runtime.** Rinx moves to makepad `db4691d0` (makepad#35, Splash + `reapply_text`) and OctoScript-Makepad `c3d53ba8` (OSM#46, stateful inputs), + the current runtime plus the two ADR 0005 additions. OctoSense shells can + therefore link it at their pins. ### Acceptance evidence (2026-09-27) -Kernel builds are octos#2555 (`cf2b4000`) in release. Models are standard-library +Kernel builds are octos#2555 (`5dad8f5f`) in release. Models are standard-library Python fixtures; no provider key or Matrix credential is used anywhere. | Criterion | Evidence | State | diff --git a/src/octos_service.rs b/src/octos_service.rs index 722330fa..606e56dc 100644 --- a/src/octos_service.rs +++ b/src/octos_service.rs @@ -184,6 +184,12 @@ fn install_standalone(service: Arc, mode: StandaloneMode) { sync_account(); } +/// Where Rinx keeps its peers' host tokens (mode 0600 files). +#[cfg_attr(not(any(feature = "octos-local", feature = "octos-remote")), allow(dead_code))] +fn peer_state_dir() -> std::path::PathBuf { + crate::app_data_dir().join("octos").join("peers") +} + fn settings_path() -> std::path::PathBuf { crate::app_data_dir().join("octos").join("assistant.json") } @@ -279,7 +285,7 @@ pub fn use_remote(url: &str, profile: &str, token: &str) -> Result<(), String> { return Err("Enter the server's access token".into()); } let connector = WsConnector::new(url.clone(), token, profile)?; - let cfg = BrokerConfig::new( + let mut cfg = BrokerConfig::new( Deployment::StandaloneRemote, profile, standalone_root(profile), @@ -287,6 +293,9 @@ pub fn use_remote(url: &str, profile: &str, token: &str) -> Result<(), String> { "Rinx", rinx_services(), ); + // The peer's host token (the kernel's credential for controlling Rinx's + // peer) is kept per server, mode 0600, so a restart resumes the peer. + cfg.state_dir = Some(peer_state_dir().join(url.host_str().unwrap_or("server"))); let service = Arc::new(Broker::new(cfg, Arc::new(connector))); let mode = StandaloneMode::Remote { url: url.to_string(), profile: profile.to_owned() }; save_mode(&mode)?; @@ -347,7 +356,7 @@ mod local { } let core = octosense_app_peers::octos_core::Core::new(options); core.launch().map_err(|e| e.to_string())?; - let cfg = BrokerConfig::new( + let mut cfg = BrokerConfig::new( Deployment::StandaloneLocal, "_main", standalone_root("_main"), @@ -355,6 +364,7 @@ mod local { "Rinx", rinx_services(), ); + cfg.state_dir = Some(peer_state_dir().join("local")); Ok(Arc::new(Broker::new(cfg, Arc::new(CoreConnector::owned(core))))) } From 82391adf228692222462fc8696a04906a7aaf3eb Mon Sep 17 00:00:00 2001 From: ymote <151983+ymote@users.noreply.github.com> Date: Sat, 26 Sep 2026 20:31:02 -0700 Subject: [PATCH 08/10] Name App Hub by the URL the OctoSense shells use One source identity for octosense-app-policy when a shell links Rinx, without URL-alias patches. Co-Authored-By: Claude Opus 5.5 (1M context) --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9051b8cf..344fc495 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7923,7 +7923,7 @@ dependencies = [ [[package]] name = "octosense-app-policy" version = "0.1.0" -source = "git+https://github.com/OctoSense-org/OctoSense-App-Hub.git?rev=46d67e51b62827a1224b1aacddc2a7b9e69185fc#46d67e51b62827a1224b1aacddc2a7b9e69185fc" +source = "git+https://github.com/OctoSense-org/OctoSense-App-Hub?rev=46d67e51b62827a1224b1aacddc2a7b9e69185fc#46d67e51b62827a1224b1aacddc2a7b9e69185fc" dependencies = [ "blake3", "makepad-widgets", diff --git a/Cargo.toml b/Cargo.toml index 290387c7..d7cfd4e7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,7 @@ octosense-app-peers = { git = "https://github.com/OctoSense-org/OctoSense-System octoscript-ui-l0 = { git = "https://github.com/OctoSense-org/Octoscript.git", rev = "68f6a9df55692b5d8ef8873a12721e279a3f40d6" } octoscript-makepad = { git = "https://github.com/OctoSense-org/Octoscript-Makepad.git", rev = "c3d53ba8bdbc219478b98b34fc73066228d9dfb3" } octoscript-widgets = { git = "https://github.com/OctoSense-org/Octoscript-Makepad.git", rev = "c3d53ba8bdbc219478b98b34fc73066228d9dfb3" } -octosense-app-policy = { git = "https://github.com/OctoSense-org/OctoSense-App-Hub.git", rev = "46d67e51b62827a1224b1aacddc2a7b9e69185fc", features = ["splash"] } +octosense-app-policy = { git = "https://github.com/OctoSense-org/OctoSense-App-Hub", rev = "46d67e51b62827a1224b1aacddc2a7b9e69185fc", features = ["splash"] } article-makepad = { path = "crates/article-makepad" } ## The OctoSense module contract. Only a host build uses it, and the host redirects ## all of makepad to its own copy (OctoSense-org/makepad rinx/octosense-module-windows). From 3648fa099616682068dc99e2813626596cb2a384 Mon Sep 17 00:00:00 2001 From: ymote <151983+ymote@users.noreply.github.com> Date: Sat, 26 Sep 2026 20:55:59 -0700 Subject: [PATCH 09/10] tests: stop octos serve's whole process group Co-Authored-By: Claude Opus 5.5 (1M context) --- tests/standalone_remote.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/standalone_remote.rs b/tests/standalone_remote.rs index b1e57114..3d19ffc3 100644 --- a/tests/standalone_remote.rs +++ b/tests/standalone_remote.rs @@ -10,6 +10,7 @@ #![cfg(feature = "octos-remote")] use std::io::BufRead; +use std::os::unix::process::CommandExt; use std::path::PathBuf; use std::sync::{Arc, Mutex}; use std::time::Duration; @@ -19,6 +20,10 @@ use octosense_app_peers::*; struct Proc(std::process::Child); impl Drop for Proc { fn drop(&mut self) { + // `octos serve` starts gateway children: stop its whole process group. + let _ = std::process::Command::new("kill") + .args(["-TERM", &format!("-{}", self.0.id())]) + .status(); let _ = self.0.kill(); let _ = self.0.wait(); } @@ -102,6 +107,7 @@ fn standalone_rinx_uses_an_explicit_authenticated_remote_server() { .args(["serve", "--port", &port.to_string(), "--auth-token", token, "--data-dir"]) .arg(&server_dir) .env("OCTOS_HOME", &server_dir) + .process_group(0) .stdout(std::process::Stdio::null()) .stderr(std::process::Stdio::null()) .spawn() From dde32297b72592b73166bb100d3cbfa6ec1c90f7 Mon Sep 17 00:00:00 2001 From: ymote <151983+ymote@users.noreply.github.com> Date: Sat, 26 Sep 2026 21:11:28 -0700 Subject: [PATCH 10/10] article-core: lock makepad-markdown at the new runtime rev Co-Authored-By: Claude Opus 5.5 (1M context) --- crates/article-core/Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/article-core/Cargo.lock b/crates/article-core/Cargo.lock index c2ede1a7..681d79e5 100644 --- a/crates/article-core/Cargo.lock +++ b/crates/article-core/Cargo.lock @@ -398,7 +398,7 @@ checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6" [[package]] name = "makepad-markdown" version = "0.1.0" -source = "git+https://github.com/OctoSense-org/makepad?rev=3fda5b6f9b48f390bd5396938a95d30ad035cd6d#3fda5b6f9b48f390bd5396938a95d30ad035cd6d" +source = "git+https://github.com/OctoSense-org/makepad?rev=db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f#db4691d0e07dc9d1e498f0430ecfaadc4ae15f8f" dependencies = [ "blake3", "comrak",