From 7873f028c5c0c935e2cafbe9b1a399ff8b5ae327 Mon Sep 17 00:00:00 2001 From: ravituringworks Date: Mon, 10 Aug 2026 20:29:23 -0700 Subject: [PATCH] chore(deps): land the Dependabot upgrades merged into feat/competitive-parity-2026 (#257) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore(deps): bump axum from 0.7.9 to 0.8.9 Bumps [axum](https://github.com/tokio-rs/axum) from 0.7.9 to 0.8.9. - [Release notes](https://github.com/tokio-rs/axum/releases) - [Changelog](https://github.com/tokio-rs/axum/blob/main/CHANGELOG.md) - [Commits](https://github.com/tokio-rs/axum/compare/axum-v0.7.9...axum-v0.8.9) --- updated-dependencies: - dependency-name: axum dependency-version: 0.8.9 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * chore(deps): bump tower-http from 0.6.11 to 0.7.0 Bumps [tower-http](https://github.com/tower-rs/tower-http) from 0.6.11 to 0.7.0. - [Release notes](https://github.com/tower-rs/tower-http/releases) - [Commits](https://github.com/tower-rs/tower-http/compare/tower-http-0.6.11...tower-http-0.7.0) --- updated-dependencies: - dependency-name: tower-http dependency-version: 0.7.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * Migrate axum 0.8 route syntax + WS message types axum 0.8 breaking changes addressed: 1. Route path syntax ':param' -> '{param}'. axum 0.8 panics at router build on any segment starting with ':' (validate_v07_paths). Migrated all :param routes in serve.rs, watch_bridge.rs, a2a_http.rs, and vibe-indexer/main.rs (route registrations + adjacent doc comments). REST doc-labels in commands.rs/app_builder.rs left as ':id' (not axum routes). 2. WebSocket Message types: Text(String)->Text(Utf8Bytes), Binary(Vec)->Binary(Bytes). Added .into() at the 8 collab-WS send/receive sites in serve.rs. tower-http 0.7 (CorsLayer/SetResponseHeaderLayer/Any) API unchanged. Verified: cargo check --workspace clean; a2a_http_bdd (3 scenarios, 12 steps) + serve_integration pass. * update branch (#157) * chore(deps): bump axum 0.7→0.8 + tower-http 0.6→0.7 (with route-syntax + WS migration) Migrates axum 0.7→0.8 and tower-http 0.6→0.7 (coupled — axum 0.8 requires tower-http 0.7). Includes the required source migration: route path syntax :param→{param} (axum 0.8 panics on :param segments) across serve.rs/watch_bridge.rs/a2a_http.rs/vibe-indexer, and WebSocket Message type conversions (Text→Utf8Bytes, Binary→Bytes). tower-http 0.7 CorsLayer/SetResponseHeaderLayer API unchanged. Subsumes #144 (tower-http bump carried here so the two coupled deps land together). Verified: cargo check --workspace clean; a2a_http_bdd 3 scenarios/12 steps pass. * chore(deps): bump onnx from 1.21.0 to 1.22.0 in /vibe-rl-py (#155) Bumps [onnx](https://github.com/onnx/onnx) from 1.21.0 to 1.22.0. - [Release notes](https://github.com/onnx/onnx/releases) - [Changelog](https://github.com/onnx/onnx/blob/main/docs/Changelog-ml.md) - [Commits](https://github.com/onnx/onnx/compare/v1.21.0...v1.22.0) --- updated-dependencies: - dependency-name: onnx dependency-version: 1.22.0 dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps): bump transformers from 4.57.6 to 5.3.0 in /vibe-rl-py (#150) Bumps [transformers](https://github.com/huggingface/transformers) from 4.57.6 to 5.3.0. - [Release notes](https://github.com/huggingface/transformers/releases) - [Commits](https://github.com/huggingface/transformers/compare/v4.57.6...v5.3.0) --- updated-dependencies: - dependency-name: transformers dependency-version: 5.3.0 dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps): bump org.jetbrains.kotlinx:kotlinx-coroutines-play-services (#133) Bumps [org.jetbrains.kotlinx:kotlinx-coroutines-play-services](https://github.com/Kotlin/kotlinx.coroutines) from 1.8.1 to 1.11.0. - [Release notes](https://github.com/Kotlin/kotlinx.coroutines/releases) - [Changelog](https://github.com/Kotlin/kotlinx.coroutines/blob/master/CHANGES.md) - [Commits](https://github.com/Kotlin/kotlinx.coroutines/compare/1.8.1...1.11.0) --- updated-dependencies: - dependency-name: org.jetbrains.kotlinx:kotlinx-coroutines-play-services dependency-version: 1.11.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps): bump androidx.compose.ui:ui-tooling-preview (#153) Bumps androidx.compose.ui:ui-tooling-preview from 1.7.6 to 1.11.4. --- updated-dependencies: - dependency-name: androidx.compose.ui:ui-tooling-preview dependency-version: 1.11.4 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps): bump gradle-wrapper in /vibewatch/VibeCodyWear (#147) Bumps [gradle-wrapper](https://github.com/gradle/gradle) from 8.10.2 to 9.6.1. - [Release notes](https://github.com/gradle/gradle/releases) - [Commits](https://github.com/gradle/gradle/compare/v8.10.2...v9.6.1) --- updated-dependencies: - dependency-name: gradle-wrapper dependency-version: 9.6.1 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Dependabot/cargo/axum 0.8.9 (#156) * chore(deps): bump axum from 0.7.9 to 0.8.9 Bumps [axum](https://github.com/tokio-rs/axum) from 0.7.9 to 0.8.9. - [Release notes](https://github.com/tokio-rs/axum/releases) - [Changelog](https://github.com/tokio-rs/axum/blob/main/CHANGELOG.md) - [Commits](https://github.com/tokio-rs/axum/compare/axum-v0.7.9...axum-v0.8.9) --- updated-dependencies: - dependency-name: axum dependency-version: 0.8.9 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * chore(deps): bump tower-http from 0.6.11 to 0.7.0 Bumps [tower-http](https://github.com/tower-rs/tower-http) from 0.6.11 to 0.7.0. - [Release notes](https://github.com/tower-rs/tower-http/releases) - [Commits](https://github.com/tower-rs/tower-http/compare/tower-http-0.6.11...tower-http-0.7.0) --- updated-dependencies: - dependency-name: tower-http dependency-version: 0.7.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * Migrate axum 0.8 route syntax + WS message types axum 0.8 breaking changes addressed: 1. Route path syntax ':param' -> '{param}'. axum 0.8 panics at router build on any segment starting with ':' (validate_v07_paths). Migrated all :param routes in serve.rs, watch_bridge.rs, a2a_http.rs, and vibe-indexer/main.rs (route registrations + adjacent doc comments). REST doc-labels in commands.rs/app_builder.rs left as ':id' (not axum routes). 2. WebSocket Message types: Text(String)->Text(Utf8Bytes), Binary(Vec)->Binary(Bytes). Added .into() at the 8 collab-WS send/receive sites in serve.rs. tower-http 0.7 (CorsLayer/SetResponseHeaderLayer/Any) API unchanged. Verified: cargo check --workspace clean; a2a_http_bdd (3 scenarios, 12 steps) + serve_integration pass. --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps-dev): bump typescript from 6.0.3 to 7.0.2 in /vibeui Bumps [typescript](https://github.com/microsoft/TypeScript) from 6.0.3 to 7.0.2. - [Release notes](https://github.com/microsoft/TypeScript/releases) - [Commits](https://github.com/microsoft/TypeScript/commits) --- updated-dependencies: - dependency-name: typescript dependency-version: 7.0.2 dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] * chore(deps): bump org.jetbrains.kotlin.android in /vibemobile/android Bumps [org.jetbrains.kotlin.android](https://github.com/JetBrains/kotlin) from 2.1.0 to 2.4.10. - [Release notes](https://github.com/JetBrains/kotlin/releases) - [Changelog](https://github.com/JetBrains/kotlin/blob/master/ChangeLog.md) - [Commits](https://github.com/JetBrains/kotlin/compare/v2.1.0...v2.4.10) --- updated-dependencies: - dependency-name: org.jetbrains.kotlin.android dependency-version: 2.4.10 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * chore(deps): bump actions/setup-python from 6 to 7 Bumps [actions/setup-python](https://github.com/actions/setup-python) from 6 to 7. - [Release notes](https://github.com/actions/setup-python/releases) - [Commits](https://github.com/actions/setup-python/compare/v6...v7) --- updated-dependencies: - dependency-name: actions/setup-python dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] * chore(deps): bump actions/setup-java from 5.3.0 to 5.7.0 Bumps [actions/setup-java](https://github.com/actions/setup-java) from 5.3.0 to 5.7.0. - [Release notes](https://github.com/actions/setup-java/releases) - [Commits](https://github.com/actions/setup-java/compare/ad2b38190b15e4d6bdf0c97fb4fca8412226d287...b6effb05e454b25005698d916606bdc6ffcbf961) --- updated-dependencies: - dependency-name: actions/setup-java dependency-version: 5.7.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * chore(deps): bump actions/setup-node from 6.4.0 to 7.0.0 Bumps [actions/setup-node](https://github.com/actions/setup-node) from 6.4.0 to 7.0.0. - [Release notes](https://github.com/actions/setup-node/releases) - [Commits](https://github.com/actions/setup-node/compare/48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e...820762786026740c76f36085b0efc47a31fe5020) --- updated-dependencies: - dependency-name: actions/setup-node dependency-version: 7.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] * chore(deps-dev): bump jsdom from 29.1.1 to 30.0.1 in /vibecoder Bumps [jsdom](https://github.com/jsdom/jsdom) from 29.1.1 to 30.0.1. - [Release notes](https://github.com/jsdom/jsdom/releases) - [Commits](https://github.com/jsdom/jsdom/compare/v29.1.1...v30.0.1) --- updated-dependencies: - dependency-name: jsdom dependency-version: 30.0.1 dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] * chore(deps): bump EmbarkStudios/cargo-deny-action from 2.0.20 to 2.1.1 Bumps [EmbarkStudios/cargo-deny-action](https://github.com/embarkstudios/cargo-deny-action) from 2.0.20 to 2.1.1. - [Release notes](https://github.com/embarkstudios/cargo-deny-action/releases) - [Commits](https://github.com/embarkstudios/cargo-deny-action/compare/bb137d7af7e4fb67e5f82a49c4fce4fad40782fe...3c6349835b2b7b196a839186cb8b78e02f7b5f25) --- updated-dependencies: - dependency-name: EmbarkStudios/cargo-deny-action dependency-version: 2.1.1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * chore(deps): bump tree-sitter from 0.25.10 to 0.26.11 Bumps [tree-sitter](https://github.com/tree-sitter/tree-sitter) from 0.25.10 to 0.26.11. - [Release notes](https://github.com/tree-sitter/tree-sitter/releases) - [Commits](https://github.com/tree-sitter/tree-sitter/compare/v0.25.10...v0.26.11) --- updated-dependencies: - dependency-name: tree-sitter dependency-version: 0.26.11 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * chore(deps): bump sysinfo from 0.36.1 to 0.39.6 Bumps [sysinfo](https://github.com/GuillaumeGomez/sysinfo) from 0.36.1 to 0.39.6. - [Changelog](https://github.com/GuillaumeGomez/sysinfo/blob/main/CHANGELOG.md) - [Commits](https://github.com/GuillaumeGomez/sysinfo/compare/v0.36.1...v0.39.6) --- updated-dependencies: - dependency-name: sysinfo dependency-version: 0.39.6 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * chore(deps): bump tokio-tungstenite from 0.28.0 to 0.29.0 Bumps [tokio-tungstenite](https://github.com/snapview/tokio-tungstenite) from 0.28.0 to 0.29.0. - [Changelog](https://github.com/snapview/tokio-tungstenite/blob/master/CHANGELOG.md) - [Commits](https://github.com/snapview/tokio-tungstenite/compare/v0.28.0...v0.29.0) --- updated-dependencies: - dependency-name: tokio-tungstenite dependency-version: 0.29.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * chore(deps): bump rustyline from 14.0.0 to 17.0.2 Bumps [rustyline](https://github.com/kkawakam/rustyline) from 14.0.0 to 17.0.2. - [Release notes](https://github.com/kkawakam/rustyline/releases) - [Changelog](https://github.com/kkawakam/rustyline/blob/master/History.md) - [Commits](https://github.com/kkawakam/rustyline/compare/v14.0.0...v17.0.2) --- updated-dependencies: - dependency-name: rustyline dependency-version: 17.0.2 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] * chore(deps-dev): bump typescript from 6.0.3 to 7.0.2 in /vibecoder Bumps [typescript](https://github.com/microsoft/TypeScript) from 6.0.3 to 7.0.2. - [Release notes](https://github.com/microsoft/TypeScript/releases) - [Commits](https://github.com/microsoft/TypeScript/commits) --- updated-dependencies: - dependency-name: typescript dependency-version: 7.0.2 dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] * chore(deps): bump chacha20poly1305 from 0.10.1 to 0.11.0 Bumps [chacha20poly1305](https://github.com/RustCrypto/AEADs) from 0.10.1 to 0.11.0. - [Commits](https://github.com/RustCrypto/AEADs/compare/chacha20poly1305-v0.10.1...chacha20poly1305-v0.11.0) --- updated-dependencies: - dependency-name: chacha20poly1305 dependency-version: 0.11.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * chore(deps): bump gradle-wrapper in /vibewatch/VibeCodyWear Bumps [gradle-wrapper](https://github.com/gradle/gradle) from 9.6.1 to 9.7.0. - [Release notes](https://github.com/gradle/gradle/releases) - [Commits](https://github.com/gradle/gradle/compare/v9.6.1...v9.7.0) --- updated-dependencies: - dependency-name: gradle-wrapper dependency-version: 9.7.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * chore(deps): bump flutter_secure_storage in /vibemobile Bumps [flutter_secure_storage](https://github.com/mogol/flutter_secure_storage) from 10.3.1 to 11.0.0. - [Release notes](https://github.com/mogol/flutter_secure_storage/releases) - [Commits](https://github.com/mogol/flutter_secure_storage/compare/v10.3.1...flutter_secure_storage-v11.0.0) --- updated-dependencies: - dependency-name: flutter_secure_storage dependency-version: 11.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] * chore(deps): bump the vibecoder-minor group across 1 directory with 5 updates Bumps the vibecoder-minor group with 5 updates in the /vibecoder directory: | Package | From | To | | --- | --- | --- | | [lucide-react](https://github.com/lucide-icons/lucide/tree/HEAD/packages/lucide-react) | `1.28.0` | `1.29.0` | | [y-websocket](https://github.com/yjs/y-websocket) | `3.0.0` | `3.1.0` | | [yjs](https://github.com/yjs/yjs) | `13.6.31` | `13.6.32` | | [monaco-editor](https://github.com/microsoft/monaco-editor) | `0.55.1` | `0.56.0` | | [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) | `8.2.0` | `8.2.1` | Updates `lucide-react` from 1.28.0 to 1.29.0 - [Release notes](https://github.com/lucide-icons/lucide/releases) - [Commits](https://github.com/lucide-icons/lucide/commits/1.29.0/packages/lucide-react) Updates `y-websocket` from 3.0.0 to 3.1.0 - [Release notes](https://github.com/yjs/y-websocket/releases) - [Commits](https://github.com/yjs/y-websocket/compare/v3.0.0...v3.1.0) Updates `yjs` from 13.6.31 to 13.6.32 - [Release notes](https://github.com/yjs/yjs/releases) - [Commits](https://github.com/yjs/yjs/compare/v13.6.31...v13.6.32) Updates `monaco-editor` from 0.55.1 to 0.56.0 - [Release notes](https://github.com/microsoft/monaco-editor/releases) - [Changelog](https://github.com/microsoft/monaco-editor/blob/main/CHANGELOG.md) - [Commits](https://github.com/microsoft/monaco-editor/compare/v0.55.1...v0.56.0) Updates `vite` from 8.2.0 to 8.2.1 - [Release notes](https://github.com/vitejs/vite/releases) - [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md) - [Commits](https://github.com/vitejs/vite/commits/v8.2.1/packages/vite) --- updated-dependencies: - dependency-name: lucide-react dependency-version: 1.29.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: vibecoder-minor - dependency-name: y-websocket dependency-version: 3.1.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: vibecoder-minor - dependency-name: yjs dependency-version: 13.6.32 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: vibecoder-minor - dependency-name: monaco-editor dependency-version: 0.56.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: vibecoder-minor - dependency-name: vite dependency-version: 8.2.1 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: vibecoder-minor ... Signed-off-by: dependabot[bot] * chore(deps): bump gradle-wrapper in /jetbrains-plugin Bumps [gradle-wrapper](https://github.com/gradle/gradle) from 9.6.1 to 9.7.0. - [Release notes](https://github.com/gradle/gradle/releases) - [Commits](https://github.com/gradle/gradle/compare/v9.6.1...v9.7.0) --- updated-dependencies: - dependency-name: gradle-wrapper dependency-version: 9.7.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * chore(deps): bump gradle-wrapper in /vibemobile/android Bumps [gradle-wrapper](https://github.com/gradle/gradle) from 9.6.1 to 9.7.0. - [Release notes](https://github.com/gradle/gradle/releases) - [Commits](https://github.com/gradle/gradle/compare/v9.6.1...v9.7.0) --- updated-dependencies: - dependency-name: gradle-wrapper dependency-version: 9.7.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * chore(deps-dev): bump vite in /vibeaichat in the vibeaichat-minor group Bumps the vibeaichat-minor group in /vibeaichat with 1 update: [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite). Updates `vite` from 8.2.0 to 8.2.1 - [Release notes](https://github.com/vitejs/vite/releases) - [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md) - [Commits](https://github.com/vitejs/vite/commits/v8.2.1/packages/vite) --- updated-dependencies: - dependency-name: vite dependency-version: 8.2.1 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: vibeaichat-minor ... Signed-off-by: dependabot[bot] * chore(deps): bump the vibedesk-minor group across 1 directory with 2 updates Bumps the vibedesk-minor group with 2 updates in the /vibedesk directory: [lucide-react](https://github.com/lucide-icons/lucide/tree/HEAD/packages/lucide-react) and [@tauri-apps/cli](https://github.com/tauri-apps/tauri). Updates `lucide-react` from 1.28.0 to 1.29.0 - [Release notes](https://github.com/lucide-icons/lucide/releases) - [Commits](https://github.com/lucide-icons/lucide/commits/1.29.0/packages/lucide-react) Updates `@tauri-apps/cli` from 2.11.2 to 2.11.4 - [Release notes](https://github.com/tauri-apps/tauri/releases) - [Commits](https://github.com/tauri-apps/tauri/compare/@tauri-apps/cli-v2.11.2...@tauri-apps/cli-v2.11.4) --- updated-dependencies: - dependency-name: "@tauri-apps/cli" dependency-version: 2.11.4 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: vibedesk-minor - dependency-name: lucide-react dependency-version: 1.29.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: vibedesk-minor ... Signed-off-by: dependabot[bot] * fix(release): `shell: bash` — the conditional export block broke Windows My previous commit replaced the single-line `run: npx tauri build` with a multi-line POSIX-shell block that exports the Apple variables conditionally. Windows runners default to PowerShell, so all three Windows bundles failed with ParserError: D:\a\_temp\.ps1:2 before tauri ever started. They had been green. GitHub provides bash on Windows runners, and the rest of the workflow already uses `shell: bash` for its cross-platform steps (see "Collect artifacts"), so this matches the existing convention rather than introducing one. Co-Authored-By: Claude Opus 5 * Use ring for RS256 JWT signing; add tests Replace rsa crate usage with ring for RS256 JWT signing in vibe-broker to avoid a timing side-channel advisory. Add pkcs8 PEM→DER helper, comprehensive unit tests that verify JWT structure and signature verification, and a test PEM fixture. Also trim syntect default features (dropping yaml-rust) and update Cargo.toml/Cargo.lock to reflect dependency changes. * build(deps): bump similar from 2.7.0 to 3.1.2 Bumps [similar](https://github.com/mitsuhiko/similar) from 2.7.0 to 3.1.2. - [Changelog](https://github.com/mitsuhiko/similar/blob/main/CHANGELOG.md) - [Commits](https://github.com/mitsuhiko/similar/compare/2.7.0...3.1.2) --- updated-dependencies: - dependency-name: similar dependency-version: 3.1.2 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] * build(deps-dev): bump typescript from 5.9.3 to 7.0.2 in /vibeaichat Bumps [typescript](https://github.com/microsoft/TypeScript) from 5.9.3 to 7.0.2. - [Release notes](https://github.com/microsoft/TypeScript/releases) - [Commits](https://github.com/microsoft/TypeScript/commits) --- updated-dependencies: - dependency-name: typescript dependency-version: 7.0.2 dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] * ci(release): make Apple signing verifiable, and stop shipping ad-hoc bundles v0.5.7 and v0.5.8 both went green, uploaded artifacts, and were killed by macOS on every user's machine: the signing step fell back to ad-hoc, and nothing downstream checked. build-cli had guarded against that since it was written; the three Tauri app bundles and the iOS .ipa had not. - Verify, don't trust. Each macOS bundle job (VibeCoder, VibeAIChat, VibeDesk) and the iOS packaging step now run `codesign --verify --deep --strict` and fail the job when the result is `Signature=adhoc` despite a certificate having been imported. Ad-hoc remains the intended outcome when no certificate is configured — the check only runs when one was. - Notarize the CLI binary. A Developer ID signature alone is not enough for a quarantined download; the ticket lives on Apple's servers for a bare Mach-O (stapling only works for .app/.dmg/.pkg), and `notarytool --wait` returns 0 only on Accepted. Skipped with a notice when credentials are absent. - APPLE_KEYCHAIN_PASSWORD is no longer required. The keychain is created, used and discarded inside the job, so a generated password protects the same nothing — and removes the silent failure where an empty one makes `security` behave differently than intended. - Signed iOS builds. Gated on all three of APPLE_TEAM_ID / APPLE_DIST_CERT_P12_BASE64 / APPLE_IOS_PROFILE_BASE64; the unsigned sideloadable .ipa still ships when they are absent. - watchOS gate checks every secret it needs, not just APPLE_TEAM_ID, which is shared with the desktop jobs — configuring desktop signing used to arm this job and then kill it on an empty provisioning profile. Its `if:` also referenced its own step output, so it always evaluated true. TestFlight upload is now gated separately from producing a signed IPA. - The ad-hoc notices say what actually happens (macOS kills the app; `xattr -dr com.apple.quarantine`) instead of "unidentified developer, right-click → Open", which does not reliably fix it. - scripts/setup-apple-signing.sh configures all of the above secrets from a Mac that holds the certificate. It pairs certificate and private key by public modulus — PEM export order is not guaranteed, and pairing by position yields a .p12 that imports cleanly and then cannot sign. - .cargo/audit.toml collects the RUSTSEC suppression list that had been copied into three places and drifted, which is how v0.5.8's release failed on an advisory only one copy carried. Co-Authored-By: Claude Opus 5 (1M context) * fix(skills): every installed build shipped an empty skill catalogue `list_skills` / `get_skill`, `GET /v1/skilllens/skills` and the SkillForge panel returned zero skills on every release binary while working fine in-tree — which read as a regression rather than what it was: the ~710 `skills/*.md` files were never packaged. The resolver's primary path was `${CARGO_MANIFEST_DIR}/skills`, baked in at compile time, so an installed `vibecli` looked for a GitHub Actions path (`/Users/runner/work/...`). The documented next fallback, `/../share/vibecli/skills`, was a convention nothing implemented: release.yml tars the bare executable, so no sibling `share/` tree ever travels with it. - The catalogue is compiled into the binary (`include_dir!`) — the only fallback that survives how the binary is actually distributed, a single file copied anywhere. It is extracted once to `~/.vibecli/bundled-skills//` and loaded from there, so `skill.path` still names a file that exists and the scoring / body-render paths that re-read it are unchanged. Extraction is version-scoped, guarded by a completeness marker so an interrupted run re-extracts rather than caching a partial tree, and prunes older versions. Deliberately not `~/.vibecli/skills`, which is the promoted-override dir. - One resolver, not two. `mcp_server` and `skillforge_index` each carried a copy of the fallback chain; both now call `skills_embedded::resolve_skills_dir()`. `VIBECLI_SKILLS_DIR` still wins and is used verbatim — an override that silently fell through to the embedded copy would hide an operator's typo. - `vibecli doctor` reports the catalogue it actually loads. The old check looked at `~/.vibecli/skills` — the override dir, not the catalogue — so it printed a benign "no directory" line throughout. It now prints the resolved path, the skill count and which rule chose it, and fails the line when the count is zero. Co-Authored-By: Claude Opus 5 (1M context) * feat(bugbot): committable fixes, full-diff coverage, and a real --bugbot flag BugBot reviewed the first 8 000 characters of a diff, said nothing about the rest, and ended its review with prose. Every competing PR-review bot ends with a fix a reviewer applies in one click. Added - Committable suggestions (`bugbot_autofix.rs`, docs/bugbot.md). Findings can now carry GitHub ```suggestion blocks. Anchors come from the diff, never from the model: GitHub applies a suggestion by replacing the exact lines the comment is anchored to, so an off-by-one anchor silently destroys code. A `PostImage` index maps path → new-line → text from the diff's own context and added lines, and a proposal that cannot be located there is refused, not guessed. Seven typed refusals (AnchorMissing, SpanTooLarge, EmptyReplacement, Unchanged, FenceInReplacement, ModelDeclined, Unparseable) are printed with the finding rather than swallowed. `AnchorVerified` means the target lines were found and the replacement is non-empty and different — nothing more, and every posted comment says the fix has not been compiled or tested, because it hasn't. - Full-diff coverage (`ReviewPlan` / `ReviewCoverage`). The diff is split per file, packed into batches that each fit the request budget, and every batch is reviewed — a small diff still costs one call, a 64 KB one up to eight. What was read is reported ("Reviewed 12/12 file(s) in 3 model call(s)"), and when it wasn't everything, the skipped and truncated files are named on stderr, appended to the commit-status description, and returned as a `coverage` object on the webhook response. - `--passes N` trades cost for recall: each batch is reviewed N times with the file order rotated, because a defect in the last file of a prompt is likelier to be missed than one in the first. Rotation is deterministic, so two runs over the same diff issue the same requests — something a randomised ordering could not promise in CI. Findings are deduplicated by location plus a normalised message, keeping the highest severity seen. - `--bugbot` exists. `bugbot.rs` had advertised `vibecli --bugbot --diff` / `--pr 123` in its module docs since it was written; no such flag existed and the only caller was the GitHub webhook. `--bugbot` reviews uncommitted changes, `--staged` the index, `--pr N` a pull request, and it exits 1 on any error-severity finding so it drops into a pre-push hook or CI step. `--propose-fixes` adds suggestions, `--apply-fixes` writes them (skipping any file that moved since the diff, printing both counts). `--pr` refuses a non-GitHub remote instead of guessing a slug that would review an unrelated repository. Fixed - `POST /webhook/github` failed open when no webhook secret was set. Signature verification ran only `if let Some(secret) = …`; with none configured, every unsigned POST was acted on. The route is public by design, and a review is not a read — it spends model budget and calls the GitHub API with the operator's token against whatever repository the payload names. Unsigned webhooks are now rejected, and the error names the command that fixes it. - The GitHub App webhook secret could not be stored encrypted. `resolve_webhook_secret` reads the ProfileStore key `github_app_webhook_secret` first, per Zero-Config First — but `set-key` validated the name against a list that omitted it and answered "unknown provider", leaving only a plaintext config.toml field and an environment variable, both of which the same rule forbids for a secret. - `[github_app] auto_fix` was a dead flag: documented, serialised, defaulted, covered by three tests, and read by no production path. It now drives the suggestion pass, and its documentation says what it actually does — it attaches committable suggestions and never pushes a commit. The webhook response gained an honest `fixes_proposed` count, which excludes findings the fixer declined. Co-Authored-By: Claude Opus 5 (1M context) * feat(daemon): wire two modules that had been counted as shipped `mcp_well_known` and the workspace half of `trust_resolution` were both written, tested, marked `#![allow(dead_code)]`, and left without a caller — present in the tree and counted as closed on the roadmap. Neither did anything. - `GET /.well-known/mcp.json` (A3) is served from the public rate-limited router. Hosts read a `.well-known` document before they hold a token, and the descriptor carries tool names and descriptions only — the same class of metadata `/models` already serves unauthenticated. `mcp_server::tool_defs()` stays the single source of truth; the route only reshapes it, and a test pins the tool count to it so the descriptor cannot drift from `tools/list`. - Workspace trust (E4) gets both an enforcement point and a way to set it, because either alone is just another unreachable module. `/trustdir allow|deny|reset` writes `~/.vibecli/trust.json`; `serve::workspace_denied` reads it in `start_agent`, after `resolve_run_root`, so the run path is gated once instead of per-handler. Deny-only, deliberately: the resolver's `default_policy` is `RequireApproval`, so honouring the full policy would make every existing workspace start prompting the moment this shipped — a Zero-Config First break for a store no user has yet. Only an explicit entry in `denied_paths` (or a parent of one) blocks a run; a missing, unreadable, or malformed store denies nothing. The tests pin that negative property first. It is `/trustdir`, not `/trust`: `/trust` is taken and scores *agents*, while this governs *directories*. Co-Authored-By: Claude Opus 5 (1M context) * fix(bugbot): a failed model call is not coverage `review_once` returned `Vec` and mapped a provider error to an empty vec, so a review that never happened was indistinguishable from one that found nothing. With the provider down, unconfigured, or rate limited, `--bugbot` printed "0 findings, 1/1 file(s) reviewed" — a clean bill of health nobody gave, on the struct written to stop exactly that. - `review_once` returns `Option>`: `None` is "the provider failed", `Some(vec![])` is "the model looked and found nothing". - `ReviewCoverage` gains `llm_calls_failed` and `files_provider_failed`, and `files_reviewed` counts only files whose batch completed a pass. `is_complete()` and `caveat()` account for them, so the caveat reaches the PR body and commit status as well as the terminal. - The terminal message distinguishes the two remedies: a call-budget skip says review a smaller change, a provider failure says check `--doctor`. Advising "try --staged" for an outage was wrong advice. - Tests cover a failing provider end to end: the file is reported unreviewed, the deterministic static scan still runs (and still reports the hardcoded key), and an empty diff still costs no model calls. Co-Authored-By: Claude Opus 5 (1M context) * feat(skills): import 433 Jobs-To-Be-Done skills — catalogue goes 710 → 1,143 A national-operating-system skill library, converted from Anthropic Agent-Skills format (a directory per skill, `SKILL.md` + frontmatter) into VibeCody's flat catalogue: 24 sector operating systems with their 204 AI-personnel role skills and 27 autonomous-machine skills, 26 industry overlays, 15 cross-cutting role archetypes, 12 strategic missions, 8 subsector packs, 108 catalogue skills, and 2 routers. Categories reuse the existing vocabulary where one fits (energy, healthcare, defense, finance, logistics, robotics) and add a domain slug where none did. - Every relative cross-reference was rewritten, because a flat catalogue has no `../..`. The source tree navigates by path — 302 references to `../../../00-framework/SKILL.md`, 266 to a role's own `../../SKILL.md`, plus directory pointers. Left alone they would send an agent to files that do not exist. Each now names the flat skill or the name glob the directory became. The import refuses to write while any path-shaped reference remains unresolved; it reports zero. - The 52 `references/*.md` companions are inlined, not dropped: they carry the controls, exception tables, and subsector maps the overlays point at. A flat catalogue can hold neither the directory nor the pointer, so each is appended as a `## Reference — ` section with headings demoted, and every pointer repointed at that section. - Triggers are derived, never invented — from the title, the bold spans the description uses to name its subject, the domain, and the explicit "trigger this skill when…" sentence the source carries. Triggers are the main signal in `skill_matches_query`, so no skill ships with none. - Pointers to files outside the skill tree (a vault note, a routing matrix, `examples/*.py`) were already dangling at the source and are reworded rather than shipped as dead ends. Also: `build.rs` now emits `cargo:rerun-if-changed=skills`. `include_dir!` tracks the contents of the files it expanded to, not the directory listing — and the existing `rerun-if-env-changed` lines had already disabled cargo's default whole-package rescan, so adding or deleting a skill would have shipped a stale embedded catalogue with nothing to notice. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * ci(security): finish the audit.toml migration — one suppression list, enforced .cargo/audit.toml landed in fe9a7e97 claiming to be the single source of truth, but both workflows still passed their own 29-flag `--ignore` lists and deny.toml carried a third copy — the drift the file was written to end was untouched. - Both workflows now run a bare `cargo audit --deny warnings`. cargo-audit reads .cargo/audit.toml from the repo root automatically. Verified empirically: with the file present the audit exits 0, with it moved aside 23 advisories fire and it exits 1, so the file is load-bearing rather than merely present. - deny.toml is named authoritative — cargo-deny cannot read audit.toml and its schema is the only one carrying a reason and review-by per entry. The ids are mirrored, and a new `Suppression lists agree` step in security.yml diffs the two sets and fails on any difference. That is what makes "they cannot disagree" true instead of aspirational; the step also fails when either extraction comes back empty, so a reflowed array cannot silently check nothing. - The lists were reconciled, not assumed equal. audit.toml was missing three ids every other copy had — RUSTSEC-2023-0071 (rsa Marvin timing sidechannel), RUSTSEC-2024-0320 (yaml-rust), RUSTSEC-2025-0134 (rustls-pemfile). rustls-pemfile fires against the current lockfile, so landing the migration without it would have turned the release audit red. - RUSTSEC-2026-0222 is dropped. audit.toml claimed it was "present in security.yml's list"; it appears there only in a comment describing the quinn-proto advisory that a regenerated lockfile once hid. quinn-proto is 0.11.15 in the lock — past the affected 0.11.14 — so suppressing it would have re-hidden a real vulnerability if it ever came back. - RUSTSEC-2026-0002 and RUSTSEC-2026-0215 were each listed twice; deduped. Two suppressions are now inert: `rsa` and `yaml-rust` are no longer in Cargo.lock at all. They are carried with a note rather than dropped, because removing a suppression in the same change that consolidates the lists is a policy change wearing a refactor's clothes. Next triage should delete them. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs(bugbot): document that a failed model call is not coverage The behaviour landed in c7a1c614; this is its documentation. Records the distinction the code makes — `Some(vec![])` versus `None`, `llm_calls` versus `llm_calls_failed` — the two terminal outputs a reader will actually see, and the two new `coverage` fields on the webhook response. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * ci(release): audit and attest the lockfile the release actually builds Both Rust jobs ran `cargo generate-lockfile` first, under a step named "Generate Cargo.lock (gitignored)". Cargo.lock is committed and has never been gitignored, and regenerating it re-resolves every dependency to the newest semver-compatible release — so both jobs described a dependency set that existed only on the runner. security.yml already documents where that leads: quinn-proto 0.11.14 (RUSTSEC-2026-0222 et al.) sat in the committed lock behind a green audit, which is why that workflow stopped regenerating. The release gate — the stricter of the two, and the one that decides whether a tag ships — had kept doing it, making the audit that mattered more the one that meant less. - The audit job verifies the lockfile instead of replacing it: `cargo metadata --locked` fails if the committed lock cannot satisfy Cargo.toml, so a stale lock stops the release rather than being silently papered over. - The SBOM job gets the same treatment, where the consequence is worse. An SBOM is an attestation of what a release contains, published so auditors can cross-reference it against future advisories. Generated from a regenerated lock it would clear — or blame — versions no artifact ever contained. - `cargo build` gains `--locked`, closing the loop: the audit verifies the committed lock and the build now refuses anything else. Without it cargo silently updates the lock when it cannot satisfy the manifest, and the shipped binary drifts from the set that was audited and published. Verified locally: `cargo metadata --locked` and `cargo tree --locked -p vibecli` both succeed against the committed lock, so none of the three changes turns the current release red. Both workflow files still parse. Not touched: ci.yml also runs `cargo generate-lockfile` before fmt / clippy / test. Same class of problem — it checks versions the repo never pins — but it gates a PR rather than a release artifact, and the three Tauri bundle jobs build through `npm run tauri build`, where `--locked` is not a flag this workflow controls. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * test(skills): assert reachability, not catalogue size `embedded_skill_count() > 1000` recorded what the catalogue happened to hold the day it was written. It goes stale on the next import, and — worse — it passes while a third of the tree is missing. How many skills ship is a product decision; what has to hold is that each one can be reached from the context it belongs to. - `embedded_tree_is_not_empty` — zero is the bug, and there is no bound above it. Same for categories: `categories().len() > 5` becomes non-empty, since how many categories the catalogue uses is also a product decision. - `every_embedded_skill_is_retrievable_by_its_own_name_and_triggers` — the property that replaces the number. A skill must come back from a `list()` query for its own name and for each trigger it declares, checked on a fixed stride (the full cross product is quadratic over every skill body). Writing it surfaced a gap the count never would have: 157 of the 1,143 skills carry no YAML frontmatter at all, so they parse to `SkillFrontmatter::default()` — no triggers, no category. All 157 predate the Jobs-To-Be-Done import; every one of its 433 skills declares both. They are not unreachable — `skill_matches_query` also substring-matches the body — but they are reachable only by accident: they never match a category filter, and they surface for a free-text query only when the words happen to appear somewhere in their prose. `every_embedded_skill_declares_triggers_and_a_category` states that invariant and is `#[ignore]`d with the reason, so the gap is recorded in the suite rather than in a comment nobody runs. Verified: 7 passed, 1 ignored. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * perf(skills): cache the built-in catalogue instead of re-reading it per call `list_skills` and `get_skill` each called `SkillCatalog::load_from_with_cwd_plugins` per MCP invocation: 1,143 file reads, ~990 YAML parses, and a `WorkspaceStore::open` — which *creates* the encrypted database, in whatever directory the MCP host happened to launch in — to answer one question. An agent calling `list_skills` three times in a turn paid all of it three times. - `load_with_cwd_plugins_cached` shares one `Arc<SkillCatalog>` per directory. - Revalidated by fingerprint, not by a timer, so authoring a skill in-tree still takes effect without a restart: file count, combined size, and newest mtime across the directory — ~7 ms over 1,143 files against ~60 ms+ to re-read and re-parse. The directory's own mtime would be a single `stat`, but it does not move when a file's contents change, which is exactly how skills are edited. - The plugin overlay is deliberately not cached — a handful of files whose enablement can change at any time, recomposed per call while the expensive built-in load is shared. With no plugin skills the shared catalogue is returned as-is, with no copy of its ~5.8 MB of bodies. - The `WorkspaceStore` open is gated on `<cwd>/.vibecli/workspace.db` already existing, so the skills path stops creating stray workspace databases in scratch directories. Verified: 27 passed, 1 ignored (the known frontmatter gap). The five new tests cover allocation reuse, invalidation on a changed body and on an added file, per-directory keying, and a missing directory reporting an error rather than an empty catalogue. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * build(deps): bump actions/checkout from 7.0.0 to 7.0.1 Bumps [actions/checkout](https://github.com/actions/checkout) from 7.0.0 to 7.0.1. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0...3d3c42e5aac5ba805825da76410c181273ba90b1) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: 7.0.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> * build(deps): bump hmac from 0.12.1 to 0.13.0 Bumps [hmac](https://github.com/RustCrypto/MACs) from 0.12.1 to 0.13.0. - [Commits](https://github.com/RustCrypto/MACs/compare/hmac-v0.12.1...hmac-v0.13.0) --- updated-dependencies: - dependency-name: hmac dependency-version: 0.13.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> * build(deps): bump p256 from 0.13.2 to 0.14.0 Bumps [p256](https://github.com/RustCrypto/elliptic-curves) from 0.13.2 to 0.14.0. - [Commits](https://github.com/RustCrypto/elliptic-curves/compare/p256/v0.13.2...p256/v0.14.0) --- updated-dependencies: - dependency-name: p256 dependency-version: 0.14.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> * build(deps): bump base64 from 0.22.1 to 0.23.1 Bumps [base64](https://github.com/marshallpierce/rust-base64) from 0.22.1 to 0.23.1. - [Changelog](https://github.com/marshallpierce/rust-base64/blob/master/RELEASE-NOTES.md) - [Commits](https://github.com/marshallpierce/rust-base64/compare/v0.22.1...v0.23.1) --- updated-dependencies: - dependency-name: base64 dependency-version: 0.23.1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> * build(deps): bump zip from 2.4.2 to 8.6.0 Bumps [zip](https://github.com/zip-rs/zip2) from 2.4.2 to 8.6.0. - [Release notes](https://github.com/zip-rs/zip2/releases) - [Changelog](https://github.com/zip-rs/zip2/blob/master/CHANGELOG.md) - [Commits](https://github.com/zip-rs/zip2/compare/v2.4.2...v8.6.0) --- updated-dependencies: - dependency-name: zip dependency-version: 8.6.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> * Sync provider lists and add 'poolside' provider Ensure new AI providers are selectable across clients and document the workflow. Updates: - Expand add-provider skill to include 8-file backend dance and client lists so providers are selectable. - Add a catalog test that verifies vscode-extension/package.json offers every catalog provider. - Add "poolside" to VS Code extension manifest and VibeAIChat labels. - Expand JetBrains provider list to mirror catalog and use it in the UI combo box. - Update AGENTS.md, CLAUDE.md, SOUL.md, README.md to reflect VibeDesk and 14 clients and to clarify surfaces to touch (Tauri handlers, tauri.conf.json, version bump, etc.). These changes fix a class of bugs where a provider was supported by the daemon but missing from client manifests, making it unselectable. * Backfill skill frontmatter and wire ACP stdio mode Adds YAML frontmatter (triggers, tools_allowed, category) to all 157 previously-missing skill files, enabling proper skill discovery and categorization. Implements the missing stdio transport for ACP (Agent Client Protocol) by wiring the complete but unreachable dispatcher to the CLI via `--acp` flag, allowing IDEs like Zed, JetBrains, Neovim, and Emacs to launch VibeCLI as an agent subprocess. Includes comprehensive ACP stdio tests and a new catalog validation test for JetBrains provider availability. * build(deps-dev): bump typescript in /vscode-extension Bumps [typescript](https://github.com/microsoft/TypeScript) from 5.9.3 to 7.0.2. - [Release notes](https://github.com/microsoft/TypeScript/releases) - [Commits](https://github.com/microsoft/TypeScript/commits) --- updated-dependencies: - dependency-name: typescript dependency-version: 7.0.2 dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> * Add explicit-trigger inline completion (ghost text) Introduce a new ghost-text completion surface that triggers only on explicit user gestures (⌘. style), replacing the keystroke-driven keystroke-driven path removed in commit 5a7eef7c for patent reasons. Changes: - New vibe_ai::ghost module with request/response types, message building, and sanitization (caps output to 12 lines, handles code fences) - Extract resolve_editing_provider() to route both diffcomplete and ghost text through the toolbar's provider/model selection, fixing a bug where diffcomplete dropped the model entirely - Add model parameter to diffcomplete_generate to pass toolbar selection through - Register ghost_complete Tauri command The ghost module intentionally carries no hidden state, edit history, or automatic triggering — only the visible prefix/suffix window and optional project memory. This keeps the boundary between explicit and automatic requests clear, with the gate living in the editor's inline-completion provider. * fix(deps): TypeScript 7 cannot resolve against typescript-eslint The Dependabot bump to typescript ~7.0.2 left vibecoder with an unresolvable dependency graph: typescript-eslint@8.66.0 peers on typescript >=4.8.4 <6.1.0, and no published typescript-eslint (8.67.0 latest) supports TS 7 yet. The bump merged textually clean, so npm was never invoked and never objected — npm install --package-lock-only fails with ERESOLVE. Restores the version this project was on before the bump (~6.0.3) and regenerates the lockfile from the manifest, so the two agree again. vibeaichat and vibedesk keep TS 7 — neither uses typescript-eslint. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(deps): same TypeScript 7 / typescript-eslint clash in vscode-extension typescript-eslint@8.57.2 peers on typescript <6.1.0. Restores ^5.3.0, the version before the Dependabot bump, and re-locks. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Add explicit-trigger ghost text inline completion Introduce an explicit-trigger "ghost text" inline completion feature. Adds /v1/ghost/complete server route and daemon->vibe_ai glue, a new vibecoder lib (ghostText.ts) with unit tests, and registers the provider + Alt+\ keybinding in the App UI (forwards provider+model). Update LSP completion context mapping to translate Monaco trigger kinds to LSP. VS Code extension: add ghostComplete command, inline provider, API client method, settings and keybinding. Gate: only responds to explicit/user trigger (no debounce or keystroke-driven requests); truncated responses are surfaced. * fix(vibeaichat): declare Vite client types so TS 7 accepts CSS imports The Dependabot typescript ^7.0.2 bump is merged here (vibeaichat has no typescript-eslint, so unlike vibecoder and vscode-extension it can take it). TS 7 raises TS2882 on side-effect imports with no declaration, and vibeaichat had no .d.ts at all — four errors on './App.css' and the @vibe/shared stylesheets. Adds the same src/vite-env.d.ts that vibecoder already carries. tsc --noEmit is clean on TypeScript 7.0.2. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Add explicit-trigger ghost text docs & tests Introduce explicit-trigger "ghost text" docs and hook up related tests and fixes. - Add docs/ghost-text.md and expose it in docs/_config.yml sidebar. - Update docs/diffcomplete.md to describe ghost-text as an explicit-trigger alternative and clarify behavior. - Add server-side tests for POST /v1/ghost/complete: unauthenticated 401 and empty-window BAD_REQUEST checks (vibecli/vibecli-cli/src/serve.rs). - Update frontend tests (DiffCompleteModal) to include the model field when sending provider so the backend preserves the host's model choice. - Add LSP mapping tests (toLspCompletionContext) to ensure Monaco trigger kinds map correctly to LSP (avoid emitting LSP's invalid 0). Rationale: document and validate the new short-form inline completion flow (explicit trigger only), and fix/test completion trigger mapping and model forwarding to avoid provider/model misrouting. --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com> --- .github/workflows/ci.yml | 34 +- .github/workflows/pages.yml | 2 +- .github/workflows/pr-bot.yml | 2 +- .github/workflows/release.yml | 44 +- .github/workflows/security.yml | 18 +- Cargo.lock | 828 ++++++++++++------ Cargo.toml | 8 +- crates/vibe-desktop-voice/Cargo.toml | 2 +- crates/vibe-profile-store/Cargo.toml | 2 +- docs/_config.yml | 3 + docs/diffcomplete.md | 12 +- docs/ghost-text.md | 114 +++ .../gradle/wrapper/gradle-wrapper.jar | Bin 48462 -> 47505 bytes .../gradle/wrapper/gradle-wrapper.properties | 2 +- vibe-memory/Cargo.toml | 2 +- vibeaichat/package-lock.json | 391 ++++++++- vibeaichat/package.json | 4 +- vibeaichat/src/vite-env.d.ts | 1 + vibecli/crates/vibe-broker/Cargo.toml | 2 +- vibecli/vibecli-cli/Cargo.toml | 10 +- vibecli/vibecli-cli/src/acp_stdio.rs | 8 + vibecli/vibecli-cli/src/serve.rs | 115 +++ vibecoder/crates/vibe-ai/src/ghost.rs | 388 ++++++++ vibecoder/crates/vibe-ai/src/lib.rs | 1 + vibecoder/crates/vibe-core/Cargo.toml | 2 +- vibecoder/package-lock.json | 599 +++++++------ vibecoder/package.json | 12 +- vibecoder/src-tauri/Cargo.toml | 6 +- vibecoder/src-tauri/src/commands.rs | 95 +- vibecoder/src-tauri/src/lib.rs | 1 + vibecoder/src/App.tsx | 58 +- .../src/components/DiffCompleteModal.tsx | 10 +- .../__tests__/DiffCompleteModal.test.tsx | 7 + vibecoder/src/lib/__tests__/ghostText.test.ts | 283 ++++++ vibecoder/src/lib/__tests__/lsp.test.ts | 59 ++ vibecoder/src/lib/ghostText.ts | 227 +++++ vibecoder/src/lib/lsp.ts | 58 +- vibedesk/package-lock.json | 102 +-- vibedesk/package.json | 2 +- .../gradle/wrapper/gradle-wrapper.properties | 2 +- vibemobile/android/settings.gradle.kts | 2 +- vibemobile/pubspec.lock | 8 +- vibemobile/pubspec.yaml | 2 +- .../gradle/wrapper/gradle-wrapper.jar | Bin 48462 -> 47505 bytes .../gradle/wrapper/gradle-wrapper.properties | 2 +- vscode-extension/package-lock.json | 360 ++++---- vscode-extension/package.json | 12 + vscode-extension/src/api-client.ts | 43 + vscode-extension/src/extension.ts | 12 + vscode-extension/src/ghost-text.ts | 188 ++++ 50 files changed, 3224 insertions(+), 921 deletions(-) create mode 100644 docs/ghost-text.md create mode 100644 vibeaichat/src/vite-env.d.ts create mode 100644 vibecoder/crates/vibe-ai/src/ghost.rs create mode 100644 vibecoder/src/lib/__tests__/ghostText.test.ts create mode 100644 vibecoder/src/lib/ghostText.ts create mode 100644 vscode-extension/src/ghost-text.ts diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8133334ed..b6799cfc2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -34,7 +34,7 @@ jobs: matrix: check: [fmt, clippy, test] steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Install Rust toolchain uses: dtolnay/rust-toolchain@631a55b12751854ce901bb631d5902ceb48146f7 # stable @@ -110,10 +110,10 @@ jobs: matrix: check: [lint, typecheck, test, build] steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Setup Node - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: ${{ env.NODE_VERSION }} @@ -154,10 +154,10 @@ jobs: matrix: check: [typecheck] steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Setup Node - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: ${{ env.NODE_VERSION }} @@ -181,10 +181,10 @@ jobs: matrix: check: [typecheck, no-inline-edit] steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Setup Node - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: ${{ env.NODE_VERSION }} @@ -212,10 +212,10 @@ jobs: matrix: check: [lint, test] steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Setup Node - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: ${{ env.NODE_VERSION }} @@ -243,7 +243,7 @@ jobs: matrix: check: [analyze, test] steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Setup Flutter uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # v2 @@ -275,10 +275,10 @@ jobs: matrix: check: [lint] steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Setup Node - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: ${{ env.NODE_VERSION }} @@ -320,7 +320,7 @@ jobs: name: Metal GPU tests (macOS) runs-on: macos-latest steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Install Rust toolchain uses: dtolnay/rust-toolchain@631a55b12751854ce901bb631d5902ceb48146f7 # stable @@ -365,10 +365,10 @@ jobs: matrix: check: [build] steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Setup Java - uses: actions/setup-java@ad2b38190b15e4d6bdf0c97fb4fca8412226d287 # v5.3.0 + uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5.7.0 with: distribution: temurin java-version: ${{ env.JAVA_VERSION }} @@ -411,10 +411,10 @@ jobs: matrix: check: [build, test] steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Setup Java - uses: actions/setup-java@ad2b38190b15e4d6bdf0c97fb4fca8412226d287 # v5.3.0 + uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5.7.0 with: distribution: temurin java-version: ${{ env.JAVA_VERSION }} diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index 31ab02407..d70540691 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -23,7 +23,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Setup Ruby uses: ruby/setup-ruby@v1 diff --git a/.github/workflows/pr-bot.yml b/.github/workflows/pr-bot.yml index 78e3231fc..69bd25cf1 100644 --- a/.github/workflows/pr-bot.yml +++ b/.github/workflows/pr-bot.yml @@ -20,7 +20,7 @@ jobs: steps: - name: Checkout repository at PR head - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: # Check out the PR branch so the agent sees the PR's code ref: refs/pull/${{ github.event.issue.number }}/head diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b9f41acdb..731bd4bdc 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -31,7 +31,7 @@ jobs: name: Security Audit runs-on: ubuntu-latest steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Install Rust toolchain uses: dtolnay/rust-toolchain@631a55b12751854ce901bb631d5902ceb48146f7 # stable @@ -74,7 +74,7 @@ jobs: needs: audit runs-on: ubuntu-latest steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Install Rust toolchain uses: dtolnay/rust-toolchain@631a55b12751854ce901bb631d5902ceb48146f7 # stable @@ -98,7 +98,7 @@ jobs: # TODO: pin to a verified SHA during Phase 3 hardening. - name: Setup Node - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: "20" @@ -121,7 +121,7 @@ jobs: # TODO: pin to a verified SHA during Phase 3 hardening. - name: Setup Python - uses: actions/setup-python@v6 + uses: actions/setup-python@v7 with: python-version: "3.12" @@ -188,7 +188,7 @@ jobs: archive: vibecli-x86_64-windows.zip steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Install Rust toolchain uses: dtolnay/rust-toolchain@631a55b12751854ce901bb631d5902ceb48146f7 # stable @@ -371,7 +371,7 @@ jobs: args: "" steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Install Rust toolchain uses: dtolnay/rust-toolchain@631a55b12751854ce901bb631d5902ceb48146f7 # stable @@ -391,7 +391,7 @@ jobs: xdg-utils - name: Setup Node.js - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: ${{ env.NODE_VERSION }} @@ -556,7 +556,7 @@ jobs: args: "" steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Install Rust toolchain uses: dtolnay/rust-toolchain@631a55b12751854ce901bb631d5902ceb48146f7 # stable @@ -576,7 +576,7 @@ jobs: xdg-utils - name: Setup Node.js - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: ${{ env.NODE_VERSION }} @@ -735,7 +735,7 @@ jobs: args: "" steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Install Rust toolchain uses: dtolnay/rust-toolchain@631a55b12751854ce901bb631d5902ceb48146f7 # stable @@ -755,7 +755,7 @@ jobs: xdg-utils - name: Setup Node.js - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: ${{ env.NODE_VERSION }} @@ -887,10 +887,10 @@ jobs: needs: audit runs-on: ubuntu-latest steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Setup Java - uses: actions/setup-java@ad2b38190b15e4d6bdf0c97fb4fca8412226d287 # v5.3.0 + uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5.7.0 with: distribution: temurin java-version: ${{ env.JAVA_VERSION }} @@ -940,7 +940,7 @@ jobs: needs: audit runs-on: macos-latest steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 # Pin Xcode 26 — iOS 26 SDK is the required build SDK from April 28, 2026. - name: Select Xcode 26 @@ -1092,10 +1092,10 @@ jobs: needs: audit runs-on: ubuntu-latest steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Setup Java - uses: actions/setup-java@ad2b38190b15e4d6bdf0c97fb4fca8412226d287 # v5.3.0 + uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5.7.0 with: distribution: temurin java-version: ${{ env.JAVA_VERSION }} @@ -1143,7 +1143,7 @@ jobs: needs: audit runs-on: macos-latest steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 # Pin Xcode 26 so builds link against the watchOS 26 SDK — required # for App Store Connect submissions from April 28, 2026 onward. @@ -1241,7 +1241,7 @@ jobs: echo "skip=false" >> "$GITHUB_OUTPUT" fi - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 if: steps.apple-secrets.outputs.skip != 'true' - name: Select Xcode 26 @@ -1381,7 +1381,7 @@ jobs: runs-on: ubuntu-24.04 continue-on-error: true steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Install Rust toolchain uses: dtolnay/rust-toolchain@631a55b12751854ce901bb631d5902ceb48146f7 # stable @@ -1418,7 +1418,7 @@ jobs: needs: audit runs-on: ubuntu-latest steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Set up Docker Buildx uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0 @@ -1451,7 +1451,7 @@ jobs: contents: read id-token: write # required for cosign keyless OIDC steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Set up Docker Buildx uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0 @@ -1521,7 +1521,7 @@ jobs: }} runs-on: ubuntu-latest steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Download all artifacts uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4 diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index 840cbbb1b..4d0e5e6ec 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -33,7 +33,7 @@ jobs: name: cargo audit (RUSTSEC advisories) runs-on: ubuntu-latest steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Install Rust toolchain uses: dtolnay/rust-toolchain@631a55b12751854ce901bb631d5902ceb48146f7 # stable @@ -100,7 +100,7 @@ jobs: name: cargo deny (licenses, sources, bans) runs-on: ubuntu-latest steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Install Rust toolchain uses: dtolnay/rust-toolchain@631a55b12751854ce901bb631d5902ceb48146f7 # stable @@ -110,7 +110,7 @@ jobs: # via tame-index 0.18.0 (release notes). Stuck on v2.0.4 made # the job fail on any transitive dep that declared # `edition = "2024"` — globset 0.4.18 in this repo, since 2026-04-xx. - uses: EmbarkStudios/cargo-deny-action@bb137d7af7e4fb67e5f82a49c4fce4fad40782fe # v2.0.20 + uses: EmbarkStudios/cargo-deny-action@3c6349835b2b7b196a839186cb8b78e02f7b5f25 # v2.1.1 with: command: check arguments: --all-features @@ -127,10 +127,10 @@ jobs: # carrying 8 high-severity advisories that nothing ever reported. path: [vibecoder, vibeaichat, vibedesk, packages/agent-sdk, vscode-extension] steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Setup Node - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: "20" @@ -181,12 +181,12 @@ jobs: name: pip-audit (vibe-rl-py) runs-on: ubuntu-latest steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Setup Python # TODO: pin to verified SHA during Phase 3 hardening (consistent with # the rest of this workflow's pin policy). - uses: actions/setup-python@v6 + uses: actions/setup-python@v7 with: python-version: "3.12" @@ -255,7 +255,7 @@ jobs: name: gitleaks (secret scanning) runs-on: ubuntu-latest steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: # Full history so gitleaks can scan past commits, not just the diff. # If the repo grows beyond ~5min scan time, switch to `fetch-depth: 1` @@ -280,7 +280,7 @@ jobs: container: image: semgrep/semgrep steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 # Three rulesets: # 1. OWASP Top 10 baseline (registry) diff --git a/Cargo.lock b/Cargo.lock index ffb7269d5..e0d4bb67c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -33,10 +33,20 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" dependencies = [ - "crypto-common", + "crypto-common 0.1.7", "generic-array", ] +[[package]] +name = "aead" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1973cfbc1a2daf9cf550e74e1f088c28e7f7d8c1e1418fb6c9dc5184b7e84c99" +dependencies = [ + "crypto-common 0.2.2", + "inout 0.2.2", +] + [[package]] name = "aes" version = "0.8.4" @@ -44,19 +54,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" dependencies = [ "cfg-if", - "cipher", + "cipher 0.4.4", "cpufeatures 0.2.17", ] +[[package]] +name = "aes" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8eb277bec05f56a0e0591f155a484cbd0f4f07ff2905051a48c72f004f7ed58" +dependencies = [ + "cipher 0.5.2", + "cpubits", + "cpufeatures 0.3.0", +] + [[package]] name = "aes-gcm" version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" dependencies = [ - "aead", - "aes", - "cipher", + "aead 0.5.2", + "aes 0.8.4", + "cipher 0.4.4", "ctr", "ghash", "subtle", @@ -161,7 +182,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96401ca08501972288ecbcde33902fce858bf73fbcbdf91dab8c3a9544e106bb" dependencies = [ "anstyle", - "unicode-width 0.2.0", + "unicode-width", ] [[package]] @@ -200,7 +221,7 @@ version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -211,7 +232,7 @@ checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -251,9 +272,6 @@ name = "arbitrary" version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" -dependencies = [ - "derive_arbitrary", -] [[package]] name = "arc-swap" @@ -616,7 +634,7 @@ dependencies = [ "serde_json", "serde_path_to_error", "serde_urlencoded", - "sha1", + "sha1 0.10.6", "sync_wrapper", "tokio", "tokio-tungstenite 0.29.0", @@ -647,9 +665,9 @@ dependencies = [ [[package]] name = "base16ct" -version = "0.2.0" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" +checksum = "fd307490d624467aa6f74b0eabb77633d1f758a7b25f12bceb0b22e08d9726f6" [[package]] name = "base64" @@ -669,6 +687,12 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "base64" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac07cdecf99051d9a5238b80f35af32cdeba5b336e55d957b318b50137e18da5" + [[package]] name = "base64ct" version = "1.8.3" @@ -779,7 +803,7 @@ version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" dependencies = [ - "digest", + "digest 0.10.7", ] [[package]] @@ -797,6 +821,16 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block-buffer" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa" +dependencies = [ + "hybrid-array", + "zeroize", +] + [[package]] name = "block-padding" version = "0.3.3" @@ -953,21 +987,11 @@ dependencies = [ [[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" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225bff33b2141874fe80d71e07d6eec4f85c5c216453dd96388240f96e1acc14" +checksum = "f3a53fac24f34a81bc9954b5d6cfce0c21e18ec6959f44f56e8e90e4bb7c346c" dependencies = [ - "cc", - "pkg-config", + "libbz2-rs-sys", ] [[package]] @@ -1065,7 +1089,7 @@ dependencies = [ "tokenizers 0.22.2", "yoke 0.8.3", "zerocopy", - "zip 8.6.0", + "zip", ] [[package]] @@ -1190,7 +1214,7 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6" dependencies = [ - "cipher", + "cipher 0.4.4", ] [[package]] @@ -1280,7 +1304,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" dependencies = [ "cfg-if", - "cipher", + "cipher 0.4.4", "cpufeatures 0.2.17", ] @@ -1291,6 +1315,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601" dependencies = [ "cfg-if", + "cipher 0.5.2", "cpufeatures 0.3.0", "rand_core 0.10.1", ] @@ -1301,13 +1326,25 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35" dependencies = [ - "aead", + "aead 0.5.2", "chacha20 0.9.1", - "cipher", - "poly1305", + "cipher 0.4.4", + "poly1305 0.8.0", "zeroize", ] +[[package]] +name = "chacha20poly1305" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b89e1c441e926b9c82a8d023f6e1b7ae0adcfaa7d621814e4d60789bac751cb" +dependencies = [ + "aead 0.6.1", + "chacha20 0.10.0", + "cipher 0.5.2", + "poly1305 0.9.1", +] + [[package]] name = "chrono" version = "0.4.45" @@ -1355,11 +1392,22 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" dependencies = [ - "crypto-common", - "inout", + "crypto-common 0.1.7", + "inout 0.1.4", "zeroize", ] +[[package]] +name = "cipher" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8cf2a2c93cd704877c0858356ed03480ff301ee950b43f1cbe4573b088bfa6c" +dependencies = [ + "block-buffer 0.12.1", + "crypto-common 0.2.2", + "inout 0.2.2", +] + [[package]] name = "clang-sys" version = "1.8.1" @@ -1439,6 +1487,12 @@ dependencies = [ "cc", ] +[[package]] +name = "cmov" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c9ea0ac24bc397ab3c98583a3c9ba74fa56b09a4449bbe172b9b1ddb016027a" + [[package]] name = "cobs" version = "0.3.0" @@ -1503,7 +1557,7 @@ dependencies = [ "encode_unicode", "libc", "once_cell", - "unicode-width 0.2.0", + "unicode-width", "windows-sys 0.59.0", ] @@ -1515,21 +1569,21 @@ checksum = "d64e8af5551369d19cf50138de61f1c42074ab970f74e99be916646777f8fc87" dependencies = [ "encode_unicode", "libc", - "unicode-width 0.2.0", + "unicode-width", "windows-sys 0.61.2", ] [[package]] name = "const-oid" -version = "0.9.6" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" [[package]] name = "constant_time_eq" -version = "0.3.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" +checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b" [[package]] name = "convert_case" @@ -1620,6 +1674,12 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "cpubits" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15b85f9c39137c3a891689859392b1bd49812121d0d61c9caf00d46ed5ce06ae" + [[package]] name = "cpufeatures" version = "0.2.17" @@ -1702,7 +1762,7 @@ dependencies = [ "rustc-hash 2.1.2", "serde", "serde_derive", - "sha2", + "sha2 0.10.9", "smallvec 1.15.1", "target-lexicon 0.13.5", "wasmtime-internal-core", @@ -1944,12 +2004,16 @@ checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" [[package]] name = "crypto-bigint" -version = "0.5.5" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +checksum = "1a52aa3fcda4e6302a9f48734f234d35d4721b96f8fe07d073f07ce9df4f0271" dependencies = [ - "generic-array", - "rand_core 0.6.4", + "cpubits", + "ctutils", + "getrandom 0.4.3", + "hybrid-array", + "num-traits", + "rand_core 0.10.1", "subtle", "zeroize", ] @@ -1961,10 +2025,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" dependencies = [ "generic-array", - "rand_core 0.6.4", "typenum", ] +[[package]] +name = "crypto-common" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" +dependencies = [ + "getrandom 0.4.3", + "hybrid-array", + "rand_core 0.10.1", +] + [[package]] name = "csscolorparser" version = "0.6.2" @@ -2041,7 +2115,17 @@ version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" dependencies = [ - "cipher", + "cipher 0.4.4", +] + +[[package]] +name = "ctutils" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5515a3834141de9eafb9717ad39eea8247b5674e6066c404e8c4b365d2a29e" +dependencies = [ + "cmov", + "subtle", ] [[package]] @@ -2114,7 +2198,7 @@ dependencies = [ "rayon", "serde", "serde_json", - "sha2", + "sha2 0.10.9", "thiserror 2.0.18", "walkdir", "which", @@ -2345,9 +2429,9 @@ checksum = "5729f5117e208430e437df2f4843f5e5952997175992d1414f94c57d61e270b4" [[package]] name = "der" -version = "0.7.10" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +checksum = "a69dedd701da44b0536442edf09c81a64b0ab97a7a4a5e3d1971f00027cbc63d" dependencies = [ "const-oid", "pem-rfc7468", @@ -2389,17 +2473,6 @@ dependencies = [ "syn 2.0.117", ] -[[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.117", -] - [[package]] name = "derive_builder" version = "0.20.2" @@ -2480,12 +2553,24 @@ version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer", - "const-oid", - "crypto-common", + "block-buffer 0.10.4", + "crypto-common 0.1.7", "subtle", ] +[[package]] +name = "digest" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" +dependencies = [ + "block-buffer 0.12.1", + "const-oid", + "crypto-common 0.2.2", + "ctutils", + "zeroize", +] + [[package]] name = "directories-next" version = "2.0.0" @@ -2524,7 +2609,7 @@ dependencies = [ "libc", "option-ext", "redox_users 0.5.2", - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -2695,16 +2780,17 @@ checksum = "e1d926b4d407d372f141f93bb444696142c29d32962ccbd3531117cf3aa0bfa9" [[package]] name = "ecdsa" -version = "0.16.9" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +checksum = "c0681a4fc24c767085329728d8dfba959af91228aa4610cca4f8ce317ba46ae0" dependencies = [ "der", - "digest", + "digest 0.11.3", "elliptic-curve", "rfc6979", "signature", "spki", + "zeroize", ] [[package]] @@ -2724,19 +2810,20 @@ dependencies = [ [[package]] name = "elliptic-curve" -version = "0.13.8" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +checksum = "9d65aa39b3a5c1c9c1b745c9a019234bb7a21b77abcb4f4d266d706e2d577d65" dependencies = [ "base16ct", "crypto-bigint", - "digest", + "crypto-common 0.2.2", + "digest 0.11.3", "ff", - "generic-array", "group", + "hybrid-array", "pem-rfc7468", "pkcs8", - "rand_core 0.6.4", + "rand_core 0.10.1", "sec1", "subtle", "zeroize", @@ -2899,7 +2986,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -3073,11 +3160,11 @@ dependencies = [ [[package]] name = "ff" -version = "0.13.1" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" +checksum = "a1f686ab92a9fb0eaf188f6c6c87b89490baa6fdb0db4544ba4dc47f7942489f" dependencies = [ - "rand_core 0.6.4", + "rand_core 0.10.1", "subtle", ] @@ -3140,6 +3227,7 @@ checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" dependencies = [ "crc32fast", "miniz_oxide", + "zlib-rs", ] [[package]] @@ -3827,7 +3915,6 @@ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", - "zeroize", ] [[package]] @@ -3836,7 +3923,7 @@ version = "0.2.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfe4fbac503b8d1f88e6676011885f34b7174f46e59956bba534ba83abded4df" dependencies = [ - "unicode-width 0.2.0", + "unicode-width", ] [[package]] @@ -3873,9 +3960,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" dependencies = [ "cfg-if", + "js-sys", "libc", "r-efi 6.0.0", "rand_core 0.10.1", + "wasm-bindgen", ] [[package]] @@ -4062,12 +4151,12 @@ dependencies = [ [[package]] name = "group" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +checksum = "7fd1a1c7a5206c5b7a3f5a0d7ccd3ff85d0c8f5133d62a02680255b0004af5f4" dependencies = [ "ff", - "rand_core 0.6.4", + "rand_core 0.10.1", "subtle", ] @@ -4314,7 +4403,7 @@ version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" dependencies = [ - "hmac", + "hmac 0.12.1", ] [[package]] @@ -4323,7 +4412,16 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest", + "digest 0.10.7", +] + +[[package]] +name = "hmac" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6303bc9732ae41b04cb554b844a762b4115a61bfaa81e3e83050991eeb56863f" +dependencies = [ + "digest 0.11.3", ] [[package]] @@ -4361,7 +4459,7 @@ dependencies = [ "html5ever 0.38.0", "tendril 0.5.0", "thiserror 2.0.18", - "unicode-width 0.2.0", + "unicode-width", ] [[package]] @@ -4435,6 +4533,17 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "135b12329e5e3ce057a9f972339ea52bc954fe1e9358ef27f95e89716fbc5424" +[[package]] +name = "hybrid-array" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "707114b52a152fa7bdb290cd7cd5912d9467273b6d74e21b8d81aca1f8533f6b" +dependencies = [ + "subtle", + "typenum", + "zeroize", +] + [[package]] name = "hyper" version = "1.10.1" @@ -4510,7 +4619,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core", + "windows-core 0.61.2", ] [[package]] @@ -4754,7 +4863,7 @@ dependencies = [ "console 0.15.11", "number_prefix", "portable-atomic", - "unicode-width 0.2.0", + "unicode-width", "web-time", ] @@ -4767,7 +4876,7 @@ dependencies = [ "console 0.16.3", "portable-atomic", "rayon", - "unicode-width 0.2.0", + "unicode-width", "unit-prefix", "web-time", ] @@ -4826,6 +4935,15 @@ dependencies = [ "generic-array", ] +[[package]] +name = "inout" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4250ce6452e92010fdf7268ccc5d14faa80bb12fc741938534c58f16804e03c7" +dependencies = [ + "hybrid-array", +] + [[package]] name = "instability" version = "0.3.12" @@ -5159,7 +5277,7 @@ dependencies = [ "rusqlite", "serde", "serde_json", - "sha2", + "sha2 0.10.9", "tempfile", "thiserror 1.0.69", "tokio", @@ -5252,6 +5370,12 @@ dependencies = [ "once_cell", ] +[[package]] +name = "libbz2-rs-sys" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34b357333733e8260735ba5894eb928c02ecc69c78715f01a8019e7fa7f2db4c" + [[package]] name = "libc" version = "0.2.189" @@ -5475,24 +5599,12 @@ dependencies = [ ] [[package]] -name = "lzma-rs" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "297e814c836ae64db86b36cf2a557ba54368d03f6afcd7d947c266692f71115e" -dependencies = [ - "byteorder", - "crc", -] - -[[package]] -name = "lzma-sys" -version = "0.1.20" +name = "lzma-rust2" +version = "0.16.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fda04ab3764e6cde78b9974eec4f779acaba7c4e84b36eca3cf77c581b85d27" +checksum = "ca93e534d1142d1d0dcca6d25fe302508a5dfb40b302802904577725ea0b695b" dependencies = [ - "cc", - "libc", - "pkg-config", + "sha2 0.11.0", ] [[package]] @@ -5606,7 +5718,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" dependencies = [ "cfg-if", - "digest", + "digest 0.10.7", ] [[package]] @@ -5885,11 +5997,11 @@ dependencies = [ "serde-saphyr", "serde_json", "serde_plain", - "sha2", + "sha2 0.10.9", "statrs", "strum 0.27.2", "symphonia", - "sysinfo", + "sysinfo 0.36.1", "tempfile", "thiserror 2.0.18", "tokenizers 0.21.4", @@ -6008,7 +6120,7 @@ dependencies = [ "safetensors 0.8.0", "serde", "serde_json", - "sysinfo", + "sysinfo 0.36.1", "thiserror 2.0.18", "tokio", "tracing", @@ -6092,7 +6204,7 @@ dependencies = [ "png 0.18.1", "serde", "thiserror 2.0.18", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -6176,6 +6288,18 @@ dependencies = [ "memoffset", ] +[[package]] +name = "nix" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" +dependencies = [ + "bitflags 2.12.1", + "cfg-if", + "cfg_aliases 0.2.1", + "libc", +] + [[package]] name = "nix" version = "0.31.3" @@ -6282,7 +6406,7 @@ version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -6611,6 +6735,17 @@ dependencies = [ "objc2-foundation", ] +[[package]] +name = "objc2-open-directory" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb82bed227edf5201dfedf072bba4015a33d3d4a98519837295a90f0a23f676d" +dependencies = [ + "objc2", + "objc2-core-foundation", + "objc2-foundation", +] + [[package]] name = "objc2-quartz-core" version = "0.3.2" @@ -6766,8 +6901,8 @@ dependencies = [ "serde", "serde_json", "serde_with", - "sha1", - "sha2", + "sha1 0.10.6", + "sha2 0.10.9", "thiserror 2.0.18", ] @@ -6913,14 +7048,15 @@ dependencies = [ [[package]] name = "p256" -version = "0.13.2" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +checksum = "d2c9239b2dbc807adbbe147e8cf72ea7450c3a0aabe62cb8e75ff4ec22e1f72a" dependencies = [ "ecdsa", "elliptic-curve", + "primefield", "primeorder", - "sha2", + "sha2 0.11.0", ] [[package]] @@ -7040,12 +7176,12 @@ checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" [[package]] name = "pbkdf2" -version = "0.12.2" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" +checksum = "112d82ceb8c5bf524d9af484d4e4970c9fd5a0cc15ba14ad93dccd28873b0629" dependencies = [ - "digest", - "hmac", + "digest 0.11.3", + "hmac 0.13.0", ] [[package]] @@ -7087,9 +7223,9 @@ dependencies = [ [[package]] name = "pem-rfc7468" -version = "0.7.0" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +checksum = "a6305423e0e7738146434843d1694d621cce767262b2a86910beab705e4493d9" dependencies = [ "base64ct", ] @@ -7140,7 +7276,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89815c69d36021a140146f26659a81d6c2afa33d216d736dd4be5381a7362220" dependencies = [ "pest", - "sha2", + "sha2 0.10.9", ] [[package]] @@ -7310,9 +7446,9 @@ dependencies = [ [[package]] name = "pkcs8" -version = "0.10.2" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +checksum = "451913da69c775a56034ea8d9003d27ee8948e12443eae7c038ba100a4f21cb7" dependencies = [ "der", "spki", @@ -7419,7 +7555,17 @@ checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" dependencies = [ "cpufeatures 0.2.17", "opaque-debug", - "universal-hash", + "universal-hash 0.5.1", +] + +[[package]] +name = "poly1305" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e2d0073b297041425c7c3df6eb4792d598a15323fe63346852b092eca02904c" +dependencies = [ + "cpufeatures 0.3.0", + "universal-hash 0.6.1", ] [[package]] @@ -7431,7 +7577,7 @@ dependencies = [ "cfg-if", "cpufeatures 0.2.17", "opaque-debug", - "universal-hash", + "universal-hash 0.5.1", ] [[package]] @@ -7488,6 +7634,12 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" +[[package]] +name = "ppmd-rust" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efca4c95a19a79d1c98f791f10aebd5c1363b473244630bb7dbde1dc98455a24" + [[package]] name = "ppv-lite86" version = "0.2.21" @@ -7522,13 +7674,31 @@ dependencies = [ "num-integer", ] +[[package]] +name = "primefield" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c555a6e4eb7d4e158fcb028c835c3b8642206ddc279b5c6b202ef9a8bdb592f4" +dependencies = [ + "crypto-bigint", + "crypto-common 0.2.2", + "ff", + "rand_core 0.10.1", + "subtle", + "zeroize", +] + [[package]] name = "primeorder" -version = "0.13.6" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +checksum = "5c9f42978c78a00e3d68f69fc03e57a234debae69da4020a4fb588fcdcd07b06" dependencies = [ "elliptic-curve", + "once_cell", + "primefield", + "serdect", + "wnaf", ] [[package]] @@ -7961,7 +8131,7 @@ dependencies = [ "thiserror 2.0.18", "unicode-segmentation", "unicode-truncate", - "unicode-width 0.2.0", + "unicode-width", ] [[package]] @@ -8024,7 +8194,7 @@ dependencies = [ "strum 0.28.0", "time", "unicode-segmentation", - "unicode-width 0.2.0", + "unicode-width", ] [[package]] @@ -8360,12 +8530,12 @@ dependencies = [ [[package]] name = "rfc6979" -version = "0.4.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +checksum = "b4a459cddafb3fe76b31fd8f1108007566c40301feb64dc7b54656eb7388172b" dependencies = [ - "hmac", - "subtle", + "crypto-bigint", + "hmac 0.13.0", ] [[package]] @@ -8539,7 +8709,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -8607,7 +8777,7 @@ dependencies = [ "security-framework", "security-framework-sys", "webpki-root-certs", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -8636,9 +8806,9 @@ checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "rustyline" -version = "14.0.0" +version = "17.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7803e8936da37efd9b6d4478277f4b2b9bb5cdb37a113e8d63222e58da647e63" +checksum = "e902948a25149d50edc1a8e0141aad50f54e22ba83ff988cf8f7c9ef07f50564" dependencies = [ "bitflags 2.12.1", "cfg-if", @@ -8648,20 +8818,20 @@ dependencies = [ "libc", "log", "memchr", - "nix 0.28.0", + "nix 0.30.1", "radix_trie 0.2.1", "rustyline-derive", "unicode-segmentation", - "unicode-width 0.1.14", + "unicode-width", "utf8parse", - "windows-sys 0.52.0", + "windows-sys 0.60.2", ] [[package]] name = "rustyline-derive" -version = "0.10.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5af959c8bf6af1aff6d2b463a57f71aae53d1332da58419e30ad8dc7011d951" +checksum = "5d66de233f908aebf9cc30ac75ef9103185b4b715c6f2fb7a626aa5e5ede53ab" dependencies = [ "proc-macro2", "quote", @@ -8833,14 +9003,14 @@ dependencies = [ [[package]] name = "sec1" -version = "0.7.3" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +checksum = "d56d437c2f19203ce5f7122e507831de96f3d2d4d3be5af44a0b0a09d8a80e4d" dependencies = [ "base16ct", + "ctutils", "der", - "generic-array", - "pkcs8", + "hybrid-array", "subtle", "zeroize", ] @@ -8860,7 +9030,7 @@ version = "5.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a62d7f86047af0077255a29494136b9aaaf697c76ff70b8e49cded4e2623c14" dependencies = [ - "aes", + "aes 0.8.4", "cbc", "futures-util", "generic-array", @@ -8869,7 +9039,7 @@ dependencies = [ "num", "once_cell", "serde", - "sha2", + "sha2 0.10.9", "zbus", ] @@ -9152,6 +9322,16 @@ dependencies = [ "unsafe-libyaml", ] +[[package]] +name = "serdect" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66cf8fedced2fcf12406bcb34223dffb92eaf34908ede12fed414c82b7f00b3e" +dependencies = [ + "base16ct", + "serde", +] + [[package]] name = "serial2" version = "0.2.37" @@ -9202,7 +9382,18 @@ checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", "cpufeatures 0.2.17", - "digest", + "digest 0.10.7", +] + +[[package]] +name = "sha1" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aacc4cc499359472b4abe1bf11d0b12e688af9a805fa5e3016f9a386dc2d0214" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "digest 0.11.3", ] [[package]] @@ -9213,7 +9404,18 @@ checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", "cpufeatures 0.2.17", - "digest", + "digest 0.10.7", +] + +[[package]] +name = "sha2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "digest 0.11.3", ] [[package]] @@ -9287,12 +9489,12 @@ dependencies = [ [[package]] name = "signature" -version = "2.2.0" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +checksum = "28d567dcbaf0049cb8ac2608a76cd95ff9e4412e1899d389ee400918ca7537f5" dependencies = [ - "digest", - "rand_core 0.6.4", + "digest 0.11.3", + "rand_core 0.10.1", ] [[package]] @@ -9341,9 +9543,12 @@ checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" [[package]] name = "similar" -version = "2.7.0" +version = "3.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa" +checksum = "85ee016af5d736b69fc89e19254540fa4b5f5492853fb5503920f084011c78b6" +dependencies = [ + "bstr", +] [[package]] name = "siphasher" @@ -9449,12 +9654,12 @@ checksum = "599b506ccc4aff8cf7844bc42cf783009a434c1e26c964432560fb6d6ad02d82" dependencies = [ "aes-gcm", "blake2", - "chacha20poly1305", + "chacha20poly1305 0.10.1", "curve25519-dalek", "getrandom 0.3.4", "ring", "rustc_version", - "sha2", + "sha2 0.10.9", "subtle", ] @@ -9465,7 +9670,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4" dependencies = [ "libc", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -9540,9 +9745,9 @@ dependencies = [ [[package]] name = "spki" -version = "0.7.3" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +checksum = "1d9efca8738c78ee9484207732f728b1ef517bbb1833d6fc0879ca898a522f6f" dependencies = [ "base64ct", "der", @@ -9609,7 +9814,7 @@ dependencies = [ "rustls", "serde", "serde_json", - "sha2", + "sha2 0.10.9", "smallvec 1.15.1", "thiserror 2.0.18", "tokio", @@ -9647,7 +9852,7 @@ dependencies = [ "quote", "serde", "serde_json", - "sha2", + "sha2 0.10.9", "sqlx-core", "sqlx-postgres", "syn 2.0.117", @@ -9673,7 +9878,7 @@ dependencies = [ "futures-util", "hex", "hkdf", - "hmac", + "hmac 0.12.1", "home", "itoa", "log", @@ -9683,7 +9888,7 @@ dependencies = [ "rand 0.8.6", "serde", "serde_json", - "sha2", + "sha2 0.10.9", "smallvec 1.15.1", "sqlx-core", "stringprep", @@ -10113,7 +10318,22 @@ dependencies = [ "ntapi", "objc2-core-foundation", "objc2-io-kit", - "windows", + "windows 0.61.3", +] + +[[package]] +name = "sysinfo" +version = "0.39.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2071df9448915b71c4fe6d25deaf1c22f12bd234f01540b77312bb8e41361e6" +dependencies = [ + "libc", + "memchr", + "ntapi", + "objc2-core-foundation", + "objc2-io-kit", + "objc2-open-directory", + "windows 0.62.2", ] [[package]] @@ -10184,8 +10404,8 @@ dependencies = [ "tao-macros", "unicode-segmentation", "url", - "windows", - "windows-core", + "windows 0.61.3", + "windows-core 0.61.2", "windows-version", "x11-dl", ] @@ -10262,7 +10482,7 @@ dependencies = [ "webkit2gtk", "webview2-com", "window-vibrancy", - "windows", + "windows 0.61.3", ] [[package]] @@ -10303,7 +10523,7 @@ dependencies = [ "semver", "serde", "serde_json", - "sha2", + "sha2 0.10.9", "syn 2.0.117", "tauri-utils", "thiserror 2.0.18", @@ -10403,7 +10623,7 @@ dependencies = [ "tauri-plugin", "thiserror 2.0.18", "url", - "windows", + "windows 0.61.3", "zbus", ] @@ -10429,7 +10649,7 @@ dependencies = [ "url", "webkit2gtk", "webview2-com", - "windows", + "windows 0.61.3", ] [[package]] @@ -10454,7 +10674,7 @@ dependencies = [ "url", "webkit2gtk", "webview2-com", - "windows", + "windows 0.61.3", "wry", ] @@ -10517,7 +10737,7 @@ dependencies = [ "getrandom 0.4.3", "once_cell", "rustix", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -10560,7 +10780,7 @@ dependencies = [ "parking_lot", "rustix", "signal-hook", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -10570,7 +10790,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "230a1b821ccbd75b185820a1f1ff7b14d21da1e442e22c0863ea5f08771a8874" dependencies = [ "rustix", - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -10619,7 +10839,7 @@ dependencies = [ "pest", "pest_derive", "phf 0.11.3", - "sha2", + "sha2 0.10.9", "signal-hook", "siphasher", "terminfo", @@ -10644,7 +10864,7 @@ checksum = "c13547615a44dc9c452a8a534638acdf07120d4b6847c8178705da06306a3057" dependencies = [ "smawk", "unicode-linebreak", - "unicode-width 0.2.0", + "unicode-width", ] [[package]] @@ -10718,6 +10938,7 @@ checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" dependencies = [ "deranged", "itoa", + "js-sys", "libc", "num-conv", "num_threads", @@ -11345,14 +11566,14 @@ dependencies = [ "png 0.18.1", "serde", "thiserror 2.0.18", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] name = "tree-sitter" -version = "0.25.10" +version = "0.26.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78f873475d258561b06f1c595d93308a7ed124d9977cb26b148c2084a4a3cc87" +checksum = "83c567a8e18ae93f20982c90370b16fd24023aeaf52f6052b96957ab253a0fec" dependencies = [ "cc", "regex", @@ -11426,7 +11647,7 @@ dependencies = [ "httparse", "log", "rand 0.9.4", - "sha1", + "sha1 0.10.6", "thiserror 2.0.18", "utf-8", ] @@ -11443,7 +11664,7 @@ dependencies = [ "httparse", "log", "rand 0.9.4", - "sha1", + "sha1 0.10.6", "thiserror 2.0.18", ] @@ -11499,7 +11720,7 @@ checksum = "f2f6fb2847f6742cd76af783a2a2c49e9375d0a111c7bef6f71cd9e738c72d6e" dependencies = [ "memoffset", "tempfile", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -11659,15 +11880,9 @@ checksum = "16b380a1238663e5f8a691f9039c73e1cdae598a30e9855f541d29b08b53e9a5" dependencies = [ "itertools 0.14.0", "unicode-segmentation", - "unicode-width 0.2.0", + "unicode-width", ] -[[package]] -name = "unicode-width" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" - [[package]] name = "unicode-width" version = "0.2.0" @@ -11698,10 +11913,20 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" dependencies = [ - "crypto-common", + "crypto-common 0.1.7", "subtle", ] +[[package]] +name = "universal-hash" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4987bdc12753382e0bec4a65c50738ffaabc998b9cdd1f952fb5f39b0048a96" +dependencies = [ + "crypto-common 0.2.2", + "ctutils", +] + [[package]] name = "unsafe-libyaml" version = "0.2.11" @@ -11886,12 +12111,12 @@ dependencies = [ "dotenvy", "futures", "hex", - "hmac", + "hmac 0.13.0", "regex", "reqwest 0.12.28", "serde", "serde_json", - "sha2", + "sha2 0.10.9", "tempfile", "thiserror 1.0.69", "tokio", @@ -11907,12 +12132,12 @@ name = "vibe-broker" version = "0.5.8" dependencies = [ "async-trait", - "base64 0.22.1", + "base64 0.23.1", "chrono", "cucumber", "futures", "hex", - "hmac", + "hmac 0.13.0", "rcgen", "reqwest 0.12.28", "ring", @@ -11920,7 +12145,7 @@ dependencies = [ "rustls-pemfile", "serde", "serde_json", - "sha2", + "sha2 0.10.9", "tempfile", "thiserror 1.0.69", "tokio", @@ -11938,8 +12163,8 @@ dependencies = [ "anyhow", "async-trait", "axum", - "base64 0.22.1", - "chacha20poly1305", + "base64 0.23.1", + "chacha20poly1305 0.11.0", "chrono", "dirs", "futures", @@ -11952,8 +12177,8 @@ dependencies = [ "serde", "serde_json", "serde_yaml", - "sha2", - "sysinfo", + "sha2 0.10.9", + "sysinfo 0.39.6", "tauri", "tauri-build", "tauri-plugin-dialog", @@ -12030,7 +12255,7 @@ dependencies = [ name = "vibe-desktop-voice" version = "0.5.8" dependencies = [ - "base64 0.22.1", + "base64 0.23.1", "reqwest 0.12.28", "serde_json", "tauri", @@ -12128,7 +12353,7 @@ dependencies = [ "anyhow", "async-trait", "bincode", - "chacha20poly1305", + "chacha20poly1305 0.11.0", "chrono", "dirs", "futures", @@ -12138,7 +12363,7 @@ dependencies = [ "rusqlite", "serde", "serde_json", - "sha2", + "sha2 0.10.9", "tempfile", "thiserror 1.0.69", "tokio", @@ -12153,12 +12378,12 @@ dependencies = [ name = "vibe-profile-store" version = "0.5.8" dependencies = [ - "chacha20poly1305", + "chacha20poly1305 0.11.0", "hex", "rand 0.10.2", "rusqlite", "serde_json", - "sha2", + "sha2 0.10.9", "tempfile", ] @@ -12236,9 +12461,9 @@ dependencies = [ "anyhow", "async-trait", "axum", - "base64 0.22.1", + "base64 0.23.1", "bytes", - "chacha20poly1305", + "chacha20poly1305 0.11.0", "chrono", "clap", "clap_complete", @@ -12253,7 +12478,7 @@ dependencies = [ "futures", "handlebars", "hex", - "hmac", + "hmac 0.13.0", "include_dir", "keyring", "kodegraph", @@ -12273,7 +12498,7 @@ dependencies = [ "serde", "serde_json", "serde_yaml", - "sha2", + "sha2 0.10.9", "skilllensai-rs", "skilloptai-rs", "snow", @@ -12284,7 +12509,7 @@ dependencies = [ "thiserror 1.0.69", "tokio", "tokio-stream", - "tokio-tungstenite 0.28.0", + "tokio-tungstenite 0.29.0", "toml 0.8.23", "tower 0.4.13", "tower-http 0.7.0", @@ -12307,7 +12532,7 @@ dependencies = [ "vibe-sandbox-native", "walkdir", "whisper-rs", - "zip 2.4.2", + "zip", ] [[package]] @@ -12633,7 +12858,7 @@ dependencies = [ "semver", "serde", "serde_derive", - "sha2", + "sha2 0.10.9", "smallvec 1.15.1", "target-lexicon 0.13.5", "wasm-encoder 0.252.0", @@ -12656,7 +12881,7 @@ dependencies = [ "rustix", "serde", "serde_derive", - "sha2", + "sha2 0.10.9", "toml 0.9.12+spec-1.1.0", "wasmtime-environ", "windows-sys 0.61.2", @@ -12808,7 +13033,7 @@ dependencies = [ "bumpalo", "leb128fmt", "memchr", - "unicode-width 0.2.0", + "unicode-width", "wasm-encoder 0.255.0", ] @@ -12932,8 +13157,8 @@ checksum = "7130243a7a5b33c54a444e54842e6a9e133de08b5ad7b5861cd8ed9a6a5bc96a" dependencies = [ "webview2-com-macros", "webview2-com-sys", - "windows", - "windows-core", + "windows 0.61.3", + "windows-core 0.61.2", "windows-implement", "windows-interface", ] @@ -12956,8 +13181,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "381336cfffd772377d291702245447a5251a2ffa5bad679c99e61bc48bacbf9c" dependencies = [ "thiserror 2.0.18", - "windows", - "windows-core", + "windows 0.61.3", + "windows-core 0.61.2", ] [[package]] @@ -12984,7 +13209,7 @@ checksum = "692daff6d93d94e29e4114544ef6d5c942a7ed998b37abdc19b17136ea428eb7" dependencies = [ "getrandom 0.3.4", "mac_address", - "sha2", + "sha2 0.10.9", "thiserror 1.0.69", "uuid 1.24.0", ] @@ -13120,7 +13345,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.48.0", ] [[package]] @@ -13150,11 +13375,23 @@ version = "0.61.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" dependencies = [ - "windows-collections", - "windows-core", - "windows-future", + "windows-collections 0.2.0", + "windows-core 0.61.2", + "windows-future 0.2.1", "windows-link 0.1.3", - "windows-numerics", + "windows-numerics 0.2.0", +] + +[[package]] +name = "windows" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "527fadee13e0c05939a6a05d5bd6eec6cd2e3dbd648b9f8e447c6518133d8580" +dependencies = [ + "windows-collections 0.3.2", + "windows-core 0.62.2", + "windows-future 0.3.2", + "windows-numerics 0.3.1", ] [[package]] @@ -13163,7 +13400,16 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" dependencies = [ - "windows-core", + "windows-core 0.61.2", +] + +[[package]] +name = "windows-collections" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b2d95af1a8a14a3c7367e1ed4fc9c20e0a26e79551b1454d72583c97cc6610" +dependencies = [ + "windows-core 0.62.2", ] [[package]] @@ -13179,15 +13425,39 @@ dependencies = [ "windows-strings 0.4.2", ] +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link 0.2.1", + "windows-result 0.4.1", + "windows-strings 0.5.1", +] + [[package]] name = "windows-future" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" dependencies = [ - "windows-core", + "windows-core 0.61.2", "windows-link 0.1.3", - "windows-threading", + "windows-threading 0.1.0", +] + +[[package]] +name = "windows-future" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d6f90251fe18a279739e78025bd6ddc52a7e22f921070ccdc67dde84c605cb" +dependencies = [ + "windows-core 0.62.2", + "windows-link 0.2.1", + "windows-threading 0.2.1", ] [[package]] @@ -13243,10 +13513,20 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" dependencies = [ - "windows-core", + "windows-core 0.61.2", "windows-link 0.1.3", ] +[[package]] +name = "windows-numerics" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e2e40844ac143cdb44aead537bbf727de9b044e107a0f1220392177d15b0f26" +dependencies = [ + "windows-core 0.62.2", + "windows-link 0.2.1", +] + [[package]] name = "windows-registry" version = "0.6.1" @@ -13420,6 +13700,15 @@ dependencies = [ "windows-link 0.1.3", ] +[[package]] +name = "windows-threading" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3949bd5b99cafdf1c7ca86b43ca564028dfe27d66958f2470940f73d86d75b37" +dependencies = [ + "windows-link 0.2.1", +] + [[package]] name = "windows-version" version = "0.1.7" @@ -13686,6 +13975,17 @@ dependencies = [ "wasmparser 0.252.0", ] +[[package]] +name = "wnaf" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab12e7090f27e2ffd9322651492942d50c2926094af30601e1964337db39daf1" +dependencies = [ + "ff", + "group", + "hybrid-array", +] + [[package]] name = "writeable" version = "0.6.3" @@ -13722,7 +14022,7 @@ dependencies = [ "once_cell", "percent-encoding", "raw-window-handle", - "sha2", + "sha2 0.10.9", "soup3", "tao-macros", "thiserror 2.0.18", @@ -13730,8 +14030,8 @@ dependencies = [ "webkit2gtk", "webkit2gtk-sys", "webview2-com", - "windows", - "windows-core", + "windows 0.61.3", + "windows-core 0.61.2", "windows-version", "x11-dl", ] @@ -13775,15 +14075,6 @@ dependencies = [ "time", ] -[[package]] -name = "xz2" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388c44dc09d76f1536602ead6d325eb532f5c122f17782bd57fb47baeeb767e2" -dependencies = [ - "lzma-sys", -] - [[package]] name = "y4m" version = "0.8.0" @@ -13983,20 +14274,6 @@ name = "zeroize" version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" -dependencies = [ - "zeroize_derive", -] - -[[package]] -name = "zeroize_derive" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] [[package]] name = "zerotrie" @@ -14033,45 +14310,36 @@ dependencies = [ [[package]] name = "zip" -version = "2.4.2" +version = "8.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fabe6324e908f85a1c52063ce7aa26b68dcb7eb6dbc83a2d148403c9bc3eba50" +checksum = "2d04a6b5381502aa6087c94c669499eb1602eb9c5e8198e534de571f7154809b" dependencies = [ - "aes", - "arbitrary", + "aes 0.9.2", "bzip2", "constant_time_eq", "crc32fast", - "crossbeam-utils", "deflate64", - "displaydoc", "flate2", - "getrandom 0.3.4", - "hmac", + "getrandom 0.4.3", + "hmac 0.13.0", "indexmap 2.14.0", - "lzma-rs", + "lzma-rust2", "memchr", "pbkdf2", - "sha1", - "thiserror 2.0.18", + "ppmd-rust", + "sha1 0.11.0", "time", - "xz2", + "typed-path", "zeroize", "zopfli", "zstd", ] [[package]] -name = "zip" -version = "8.6.0" +name = "zlib-rs" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d04a6b5381502aa6087c94c669499eb1602eb9c5e8198e534de571f7154809b" -dependencies = [ - "crc32fast", - "indexmap 2.14.0", - "memchr", - "typed-path", -] +checksum = "34b31d188d9d685a4f9c7b46d6e36631b07058d2cfe190267adce54dc230bf12" [[package]] name = "zmij" diff --git a/Cargo.toml b/Cargo.toml index 090d36112..ef4d5739f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -65,7 +65,7 @@ anyhow = "1.0" thiserror = "1.0" # Diff -similar = { version = "2.6", features = ["inline"] } +similar = { version = "3.1", features = ["inline"] } # Git git2 = { version = "0.21.0", features = ["vendored-openssl"] } @@ -116,12 +116,12 @@ rusqlite = { version = "0.40", features = ["bundled"] } # Crypto (AWS SigV4 signing) sha2 = "0.10" -hmac = "0.12" -p256 = { version = "0.13", features = ["ecdsa"] } +hmac = "0.13" +p256 = { version = "0.14", features = ["ecdsa"] } hex = "0.4" # Code knowledge graph (kodegraph) — incremental AST-based symbol/edge graphs -tree-sitter = "0.25" +tree-sitter = "0.26" tree-sitter-rust = "0.24" tree-sitter-typescript = "0.23" tree-sitter-python = "0.25" diff --git a/crates/vibe-desktop-voice/Cargo.toml b/crates/vibe-desktop-voice/Cargo.toml index c5b9d298b..18f20183f 100644 --- a/crates/vibe-desktop-voice/Cargo.toml +++ b/crates/vibe-desktop-voice/Cargo.toml @@ -10,7 +10,7 @@ description = "Voice-input Tauri commands shared by the VibeCody desktop shells tauri = { version = "2" } serde_json = { workspace = true } reqwest = { workspace = true } -base64 = "0.22" +base64 = "0.23" [dev-dependencies] tokio = { workspace = true } diff --git a/crates/vibe-profile-store/Cargo.toml b/crates/vibe-profile-store/Cargo.toml index b886a8c0d..c8d60e93c 100644 --- a/crates/vibe-profile-store/Cargo.toml +++ b/crates/vibe-profile-store/Cargo.toml @@ -7,7 +7,7 @@ license.workspace = true description = "Encrypted profile settings store (~/.vibecli/profile_settings.db) — API keys, provider config, and UI prefs." [dependencies] -chacha20poly1305 = "0.10" +chacha20poly1305 = "0.11" rand = "0.10" rusqlite = { workspace = true } serde_json = { workspace = true } diff --git a/docs/_config.yml b/docs/_config.yml index 70c19d778..7eee0243b 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -103,6 +103,9 @@ sidebar: - title: Diffcomplete (⌘.) icon: edit-3 url: /diffcomplete/ + - title: 'Ghost text (⌥\)' + icon: zap + url: /ghost-text/ - title: BugBot icon: bug url: /bugbot/ diff --git a/docs/diffcomplete.md b/docs/diffcomplete.md index 588c9bed8..2e1be928e 100644 --- a/docs/diffcomplete.md +++ b/docs/diffcomplete.md @@ -4,9 +4,11 @@ title: Diffcomplete (⌘.) permalink: /diffcomplete/ --- -> AI editing without ghost-text. Press **⌘.** anywhere in the editor, describe the change you want, review the unified diff hunk-by-hunk, accept or reject what you like. +> AI editing you review before it lands. Press **⌘.** anywhere in the editor, describe the change you want, review the unified diff hunk-by-hunk, accept or reject what you like. -Diffcomplete is VibeCody's only AI code-editing surface. It deliberately replaces keystroke-driven inline completions with an explicit-trigger, diff-output flow — better for review and better for safety than FIM / next-edit / ghost-text systems. +Diffcomplete is VibeCody's AI code-editing surface for changes worth reviewing. It deliberately replaces *keystroke-driven* inline completions with an explicit-trigger, diff-output flow — better for review and better for safety than FIM / next-edit / ghost-text systems. + +It is no longer the only AI editing surface: [Ghost text (⌥\)](/ghost-text/) adds a short inline completion at the cursor. Both are explicit-trigger — neither fires while you type — but they differ in output and review: diffcomplete returns a reviewable diff, ghost text returns a suggestion you accept with Tab. --- @@ -20,7 +22,7 @@ Diffcomplete is VibeCody's only AI code-editing surface. It deliberately replace 6. Per hunk: **Accept** keeps the change, **Reject** drops it, **Edit** lets you tweak the proposed text in place. 7. Click **Apply** to write the accepted hunks back to the file. -That's it. There is no other AI editing surface in VibeCody. If something looks like inline completion, it isn't — it's a static lint or formatting hint. +That's it. The only other AI editing surface is [ghost text](/ghost-text/), which you must also press a key to summon. If a suggestion appears that you did *not* ask for, it isn't AI — it's LSP IntelliSense, a static lint, or a formatting hint. --- @@ -210,12 +212,12 @@ User content (instruction text, file paths) is **not** logged at any level — o For clarity (and because we removed these on purpose): -- **Not** keystroke-driven ghost text. There is no `registerInlineCompletionsProvider` path in VibeCody. +- **Not** ghost text of any kind. VibeCody does register an inline-completions provider (see [ghost text](/ghost-text/)), but it answers only the editor's *explicit* trigger kind — typing never reaches it. - **Not** FIM (fill-in-middle). The model receives prefix + selection + suffix as discrete labeled regions, not a single FIM template. - **Not** next-edit prediction. The model only sees the current file state, never your past edits. - **Not** auto-retrieval. Files in context come from your explicit picker. There is no embedding search, no call-graph walker, no symbol-server probe. -Diffcomplete is a deliberate, claim-distant alternative to those patterns. If you want a different shape of AI editing, that is a feature request — but the answer will not be re-introducing ghost text. +Diffcomplete is a deliberate, claim-distant alternative to those patterns. Ghost text was later added back in an explicit-trigger form that keeps the same distinctions — no keystroke trigger, no edit history, no auto-retrieval — while restoring Tab-to-accept for short completions. --- diff --git a/docs/ghost-text.md b/docs/ghost-text.md new file mode 100644 index 000000000..5419de4a6 --- /dev/null +++ b/docs/ghost-text.md @@ -0,0 +1,114 @@ +--- +layout: page +title: Ghost text (⌥\) +permalink: /ghost-text/ +--- + +> Inline AI completion that only appears when you ask for it. Press **⌥\\** at the cursor, read the grey suggestion, press **Tab** to accept or **Esc** to dismiss. + +Ghost text is VibeCody's short-form AI completion. It renders inline at the cursor and accepts with Tab — the ergonomics people expect from a modern editor — but it is **explicit-trigger only**: nothing is requested, and nothing appears, while you type. + +For a larger change you want to review hunk-by-hunk, use [Diffcomplete (⌘.)](/diffcomplete/) instead. + +--- + +## Quick start + +1. Open a file in **VibeCoder**, or any file in **VS Code** with the VibeCLI extension installed. +2. Put the cursor where the code should go. +3. Press **⌥\\** (Alt-Backslash on every platform). Or run **AI: Inline Completion at Cursor** from the command palette. +4. A grey suggestion appears inline. +5. **Tab** accepts it. **Esc** dismisses it. Typing anything else dismisses it too. + +If nothing appears, the model decided nothing belonged at that cursor — that is a normal answer, not an error. + +--- + +## Why it looks like other tools but isn't + +VibeCody removed its previous ghost-text implementation on purpose: that one ran on a debounce timer after every keystroke, kept a rolling buffer of your recent edits, and used them to predict the next one. This one keeps the presentation and drops all of that. + +| | Removed (keystroke-driven) | Current (explicit-trigger) | +|---|---|---| +| Trigger | debounce timer after each keystroke | **⌥\\ only** | +| Sees your edit history | yes, a rolling buffer | **no — nothing is retained between requests** | +| Auto-retrieval of other files | yes, embedding search | **no** | +| Requests while you type | continuously | **zero** | +| Accept | Tab | Tab | + +The guarantee is one line of code in each editor, and it is the same line conceptually: the inline-completion provider is consulted by the editor constantly, and it returns nothing unless the trigger kind is the explicit one. + +> **For contributors:** the enum is inverted between the two hosts. Monaco has `InlineCompletionTriggerKind = { Automatic: 0, Explicit: 1 }`; VS Code has `{ Invoke: 0, Automatic: 1 }`. The same names carry opposite numbers, so a literal comparison copied from one host to the other gates on exactly the wrong half and fires on every keystroke. Always compare against the named member. Each host has its own gate for this reason — `vibecoder/src/lib/ghostText.ts` and `vscode-extension/src/ghost-text.ts`. + +--- + +## What gets sent + +Per press, one request carrying: + +- **Prefix** — up to 160 lines before the cursor. +- **Suffix** — up to 60 lines after the cursor. +- **File path and language**, for the prompt header. +- **Project memory** — your author-written `VIBECLI.md` / `AGENTS.md` / `CLAUDE.md`, the same audit-restricted source diffcomplete uses. Never auto-extracted state. + +Nothing else. No edit history, no telemetry about what you accepted or rejected, no embedding search. + +The response is capped at 12 lines (`vibe_ai::ghost::MAX_COMPLETION_LINES`). When the cap clips a suggestion the editor says so — accept what you have and press ⌥\\ again to continue. + +--- + +## Provider and model + +Ghost text is provider-agnostic and never defaults to a single vendor. + +- **VibeCoder** uses the provider selected in the toolbar, with that provider's registry default model. With no provider selected, ⌥\\ tells you to pick one rather than silently calling anything. +- **VS Code** uses the `vibecli.provider` and `vibecli.model` settings. The daemon only honours the override when **both** are set — leave `vibecli.model` empty and the daemon uses whichever provider and model it was started with. + +--- + +## Architecture + +``` +[ ⌥\ press ] + │ + ▼ +editor.action.inlineSuggest.trigger (host built-in) + │ + ▼ +inline-completion provider ── trigger kind is Automatic? ──► return nothing + │ + │ explicit + ▼ +VibeCoder: ghost_complete (Tauri command) +VS Code: POST /v1/ghost/complete (daemon, bearer auth) + │ + ▼ +vibe_ai::ghost::generate() + │ + ├─► system prompt demanding bare insertion text + ├─► prefix / cursor / suffix as labeled regions + ├─► project memory as a separate system message + │ + ▼ +sanitize_completion() — unwraps stray code fences, caps at 12 lines, + preserves leading indentation +``` + +Leading whitespace is deliberately preserved: at a cursor sitting at column 0 of an indented block, the indentation *is* the first thing that belongs there. + +--- + +## What ghost text is NOT + +- **Not** keystroke-driven. There is no debounce timer to tune and no on-type path to disable, because none is installed. +- **Not** FIM. The model receives prefix and suffix as discrete labeled regions, not a single fill-in-middle template. +- **Not** next-edit prediction. Each request is independent; nothing about your previous edits or previous suggestions is carried forward. +- **Not** auto-retrieval. No embedding search, no call-graph walk, no symbol-server probe. + +--- + +## Related + +- **Source:** [`vibecoder/crates/vibe-ai/src/ghost.rs`](https://github.com/TuringWorks/vibecody/blob/main/vibecoder/crates/vibe-ai/src/ghost.rs) · [`vibecoder/src/lib/ghostText.ts`](https://github.com/TuringWorks/vibecody/blob/main/vibecoder/src/lib/ghostText.ts) · [`vscode-extension/src/ghost-text.ts`](https://github.com/TuringWorks/vibecody/blob/main/vscode-extension/src/ghost-text.ts) +- **Route:** `POST /v1/ghost/complete` (requires the daemon bearer token) +- **Companion surface:** [Diffcomplete (⌘.)](/diffcomplete/) diff --git a/jetbrains-plugin/gradle/wrapper/gradle-wrapper.jar b/jetbrains-plugin/gradle/wrapper/gradle-wrapper.jar index b1b8ef56b44f16b14dc800fa8103a6d89abb526f..eddabd2eef8d94a5437d6168ff9c87a78ff725b3 100644 GIT binary patch delta 39079 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 F{Rc_uT_ykk delta 40101 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 diff --git a/jetbrains-plugin/gradle/wrapper/gradle-wrapper.properties b/jetbrains-plugin/gradle/wrapper/gradle-wrapper.properties index a351597e6..1e922f407 100644 --- a/jetbrains-plugin/gradle/wrapper/gradle-wrapper.properties +++ b/jetbrains-plugin/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.6.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.7.0-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/vibe-memory/Cargo.toml b/vibe-memory/Cargo.toml index b70892707..6c2d406f1 100644 --- a/vibe-memory/Cargo.toml +++ b/vibe-memory/Cargo.toml @@ -21,7 +21,7 @@ async-trait = "0.1" rusqlite = { version = "0.40", features = ["bundled"], optional = true } tokio = { version = "1", features = ["rt-multi-thread", "sync", "fs", "macros"] } -chacha20poly1305 = { version = "0.10", optional = true } +chacha20poly1305 = { version = "0.11", optional = true } getrandom = { version = "0.4", optional = true } sha2 = "0.10" diff --git a/vibeaichat/package-lock.json b/vibeaichat/package-lock.json index 43ab5af78..075b86c29 100644 --- a/vibeaichat/package-lock.json +++ b/vibeaichat/package-lock.json @@ -1,12 +1,12 @@ { "name": "vibeaichat", - "version": "0.5.7", + "version": "0.5.8", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "vibeaichat", - "version": "0.5.7", + "version": "0.5.8", "dependencies": { "@tauri-apps/api": "^2", "@tauri-apps/plugin-opener": "^2", @@ -21,8 +21,8 @@ "@types/react": "^19.2.18", "@types/react-dom": "^19.2.4", "@vitejs/plugin-react": "^6.0.5", - "typescript": "^5.6.2", - "vite": "^8.2.0" + "typescript": "^7.0.2", + "vite": "^8.2.1" } }, "node_modules/@oxc-project/types": { @@ -622,6 +622,346 @@ "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", "license": "MIT" }, + "node_modules/@typescript/typescript-aix-ppc64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-aix-ppc64/-/typescript-aix-ppc64-7.0.2.tgz", + "integrity": "sha512-MTKKkWB7p/0E9xi1d1tHtZ5PiLkGEMIq88pK2CubZjOsLtYTLqhgIgi6zepFa+9GHZ6h05NMCkQxGKiPXMxXtQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-darwin-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-darwin-arm64/-/typescript-darwin-arm64-7.0.2.tgz", + "integrity": "sha512-gowzar9MwS/aRWp6f3a4KUqzRjAZjOsmGNCM6LcTgXum+dBfgsBVMN+AgvOCCbguXyick6LJhpBszxMebJ8syA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-darwin-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-darwin-x64/-/typescript-darwin-x64-7.0.2.tgz", + "integrity": "sha512-SZ9xZInqApNlNGc9s0W1VSsktYSOe9cFqNOIqmN1Gs8SmkjKZYFt017G4VwPxASInODuAdbTW7sXiFUf893RgA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-freebsd-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-freebsd-arm64/-/typescript-freebsd-arm64-7.0.2.tgz", + "integrity": "sha512-W5NH4y/J0plIIS5b2xvTEkU7JFxyqdMAOgf+Ilhl0vHQXKO5dZoxd+C/jEtq56c4F3wk71RB4BMRQ2XdI+bwYQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-freebsd-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-freebsd-x64/-/typescript-freebsd-x64-7.0.2.tgz", + "integrity": "sha512-UMGDx5sTpzNw3WiPebH7l90IWfJggEd+egHt/q6p7/Cm3zqoV7VxkGXt+3DxPIw8CcmvAB0j3sVVfbhX+M4Tpw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-arm": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-arm/-/typescript-linux-arm-7.0.2.tgz", + "integrity": "sha512-gffT3xPz9sR7j/YJExkyPntrI0P2EP9XbOyWzth2/Gs0RstK+90RBcO0ncXoXy/beYll1SXw846Nf2zdnEz0QQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-arm64/-/typescript-linux-arm64-7.0.2.tgz", + "integrity": "sha512-Qh4eU4/y3yDjnfjjyPYihMj5/ODIlmt+Bzu17OI+fiSRDW57QmU5SiN63exPRNJPKUzcc1INa1NXdrJ+MqHjUQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-loong64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-loong64/-/typescript-linux-loong64-7.0.2.tgz", + "integrity": "sha512-uEHck9i8hoAzXPiYRib1O7miOnz23SxIeVl6F4LXox+qov1K35jHcEW6VHKvZI+pyvl7fZEP4MCU5LYvIq1GuQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-mips64el": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-mips64el/-/typescript-linux-mips64el-7.0.2.tgz", + "integrity": "sha512-R4KvAMnE43W5Qeqb0Ly56O3mWMWIAgsMyz36DCaycd5nbg/9kzm0liw3JocfRqyJY0KPmzFjbswozXyW0DnIYA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-ppc64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-ppc64/-/typescript-linux-ppc64-7.0.2.tgz", + "integrity": "sha512-DORx5b3sd/4S7eayxm4FQv+A7CrkUIGRaHiwI8oiHTAI1fAPWhF4J0vAlkC8biAlHSVVwxMQ3tjZ2/DVbnQiiA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-riscv64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-riscv64/-/typescript-linux-riscv64-7.0.2.tgz", + "integrity": "sha512-wf0jqEDOjrPRnKwYRyyJDRo11KMbvMFrU+q4zqKyChODBzvlkbhNQfKvLxQCcwTpdDaXSHZTVuh0JoCrKCUMHQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-s390x": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-s390x/-/typescript-linux-s390x-7.0.2.tgz", + "integrity": "sha512-IkwJc3L7yhytWd/ewjyxNDfOmswCm9GWMJT/ue/dU4aZNbwZeYAetq42VyLmsmSjvoX7z74X6ZaYCtzAr0EuGw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-x64/-/typescript-linux-x64-7.0.2.tgz", + "integrity": "sha512-EYdf2cNg7rgCWJnxCdJ+F3V39O8ihb37eHAu1LK8oAFizgTQbPOK7zHHXbPt8rX24COqODXeI3sIf0fCXG7H/A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-netbsd-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-netbsd-arm64/-/typescript-netbsd-arm64-7.0.2.tgz", + "integrity": "sha512-+polYF4MF04aPpO5FTkHran9yUQDSXqy5GiSDKpsll5jy3l3+g9QLhpf39T+ePtefhXLOGrLl0QIjkQP6VnelA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-netbsd-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-netbsd-x64/-/typescript-netbsd-x64-7.0.2.tgz", + "integrity": "sha512-8YIT0EHM/3dq10ZOVF/A7pc/YSMtbcecct4rWtexrnSCHOPcpC2KTLXfTCR6vDpnSiY12heNb1GiN/wu+T/FyA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-openbsd-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-openbsd-arm64/-/typescript-openbsd-arm64-7.0.2.tgz", + "integrity": "sha512-APT8+ClYnuYm1u9+kgGXoMj2VzWzcymwh2gNSQVySHfkRDGOTVkoWLjCmOQSaO+PoqQ57B0flRp9SA+7GnnkzQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-openbsd-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-openbsd-x64/-/typescript-openbsd-x64-7.0.2.tgz", + "integrity": "sha512-yX7s+Q0Dln0Dt9tEzZsAjXXR/+ytBM7AlglaqyeMPxQszJ1JhlJdZ6jLA+IzldHtflX81em7lDao1xXu+aRRkg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-sunos-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-sunos-x64/-/typescript-sunos-x64-7.0.2.tgz", + "integrity": "sha512-dLJDGaLZ1D4HPQn62u1n8mBDkJREwMsAkCdkwd4Ieqw+x3TUyTsqY0YiBCtE6H6OzzgGk3iuZ3vFWRS+E8/d1g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-win32-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-win32-arm64/-/typescript-win32-arm64-7.0.2.tgz", + "integrity": "sha512-Gyl1Vy6OsWesLzmq+EP0Fb7b4Nid5232AvcA2SFcdYreldpNtYFFofPjnt62y9hQy7VTaZp65ICJjuAQRaVcIQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-win32-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-win32-x64/-/typescript-win32-x64-7.0.2.tgz", + "integrity": "sha512-0BQ3HkAHHlKLSp1qRvf3SUhGpGsDuhB/jgFw75guyqbxJqEaS0Cw/VFO8i2nHglJUzQCRtMMR/IBAKE3ETMC4g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=16.20.0" + } + }, "node_modules/@ungap/structured-clone": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.3.tgz", @@ -2452,17 +2792,38 @@ } }, "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-7.0.2.tgz", + "integrity": "sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA==", "dev": true, "license": "Apache-2.0", "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" + "tsc": "bin/tsc" }, "engines": { - "node": ">=14.17" + "node": ">=16.20.0" + }, + "optionalDependencies": { + "@typescript/typescript-aix-ppc64": "7.0.2", + "@typescript/typescript-darwin-arm64": "7.0.2", + "@typescript/typescript-darwin-x64": "7.0.2", + "@typescript/typescript-freebsd-arm64": "7.0.2", + "@typescript/typescript-freebsd-x64": "7.0.2", + "@typescript/typescript-linux-arm": "7.0.2", + "@typescript/typescript-linux-arm64": "7.0.2", + "@typescript/typescript-linux-loong64": "7.0.2", + "@typescript/typescript-linux-mips64el": "7.0.2", + "@typescript/typescript-linux-ppc64": "7.0.2", + "@typescript/typescript-linux-riscv64": "7.0.2", + "@typescript/typescript-linux-s390x": "7.0.2", + "@typescript/typescript-linux-x64": "7.0.2", + "@typescript/typescript-netbsd-arm64": "7.0.2", + "@typescript/typescript-netbsd-x64": "7.0.2", + "@typescript/typescript-openbsd-arm64": "7.0.2", + "@typescript/typescript-openbsd-x64": "7.0.2", + "@typescript/typescript-sunos-x64": "7.0.2", + "@typescript/typescript-win32-arm64": "7.0.2", + "@typescript/typescript-win32-x64": "7.0.2" } }, "node_modules/unified": { @@ -2581,16 +2942,16 @@ } }, "node_modules/vite": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/vite/-/vite-8.2.0.tgz", - "integrity": "sha512-pn+CFpM0lwDeKwmOq1ZaBK/9sjorZcgqxki6MbY/jPEVd9vichIlmlD4HmQ5wdP5EgqQCFRaACBxMC7uEGc6lQ==", + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.2.1.tgz", + "integrity": "sha512-EU/eS7BH3XROHh2YnBefjM6DBKA6ZeMZEYQbj7NLWg5wHYlhB8B/Mayd5XsgWq+NFYccDOTemRpdETWR6Ka/lw==", "dev": true, "license": "MIT", "dependencies": { "lightningcss": "^1.33.0", "picomatch": "^4.0.5", - "postcss": "^8.5.23", - "rolldown": "~1.2.0", + "postcss": "^8.5.25", + "rolldown": "~1.2.1", "tinyglobby": "^0.2.17" }, "bin": { diff --git a/vibeaichat/package.json b/vibeaichat/package.json index c3bba11ab..776fbfcfa 100644 --- a/vibeaichat/package.json +++ b/vibeaichat/package.json @@ -26,7 +26,7 @@ "@types/react": "^19.2.18", "@types/react-dom": "^19.2.4", "@vitejs/plugin-react": "^6.0.5", - "typescript": "^5.6.2", - "vite": "^8.2.0" + "typescript": "^7.0.2", + "vite": "^8.2.1" } } diff --git a/vibeaichat/src/vite-env.d.ts b/vibeaichat/src/vite-env.d.ts new file mode 100644 index 000000000..11f02fe2a --- /dev/null +++ b/vibeaichat/src/vite-env.d.ts @@ -0,0 +1 @@ +/// <reference types="vite/client" /> diff --git a/vibecli/crates/vibe-broker/Cargo.toml b/vibecli/crates/vibe-broker/Cargo.toml index 8884876e7..adec1670d 100644 --- a/vibecli/crates/vibe-broker/Cargo.toml +++ b/vibecli/crates/vibe-broker/Cargo.toml @@ -27,7 +27,7 @@ reqwest = { workspace = true } # RS256 JWT signing. Already in the tree via rcgen + rustls, so this is a # direct declaration of something we were compiling anyway, not a new dep. ring = "0.17" -base64 = "0.22" +base64 = "0.23" async-trait = { workspace = true } [dev-dependencies] diff --git a/vibecli/vibecli-cli/Cargo.toml b/vibecli/vibecli-cli/Cargo.toml index 2f8266e1c..953eb6475 100644 --- a/vibecli/vibecli-cli/Cargo.toml +++ b/vibecli/vibecli-cli/Cargo.toml @@ -61,10 +61,10 @@ anyhow.workspace = true serde_json.workspace = true tracing.workspace = true tracing-subscriber = { workspace = true, features = ["env-filter"] } -rustyline = { version = "14.0", features = ["derive"] } +rustyline = { version = "17.0", features = ["derive"] } dirs = "6.0" futures = "0.3" -tokio-tungstenite = { version = "0.28", features = ["connect"] } +tokio-tungstenite = { version = "0.29", features = ["connect"] } crossterm = { workspace = true, features = ["event-stream"] } serde = { workspace = true, features = ["derive"] } toml = "0.8" @@ -130,12 +130,12 @@ subtle = "2.5" dashmap = "6" hex.workspace = true uuid.workspace = true -base64 = "0.22" +base64 = "0.23" keyring = "4" -chacha20poly1305 = "0.10" +chacha20poly1305 = "0.11" chrono = { version = "0.4", features = ["serde"] } clap_complete = "4" -zip = "2" +zip = "8" handlebars = "6" socket2 = "0.6" snow = "0.10" diff --git a/vibecli/vibecli-cli/src/acp_stdio.rs b/vibecli/vibecli-cli/src/acp_stdio.rs index bdc666847..e929d40c7 100644 --- a/vibecli/vibecli-cli/src/acp_stdio.rs +++ b/vibecli/vibecli-cli/src/acp_stdio.rs @@ -125,7 +125,14 @@ impl AcpResponse { /// `prompt` slice. #[derive(Debug, Clone, Default)] pub struct AcpSession { + // Never read today: the session id is also the map key, and `mode` is + // written by `setSessionMode`, which is still `MethodNotImplemented`. + // Kept as targeted allows rather than a file-level one so genuinely new + // dead code still warns — the blanket allow on this module is exactly + // what let it sit unreachable for months. + #[allow(dead_code)] pub id: String, + #[allow(dead_code)] pub mode: String, } @@ -150,6 +157,7 @@ impl AcpServer { } /// Convenience for tests: how many sessions are currently held. + #[allow(dead_code)] pub fn session_count(&self) -> usize { self.state.lock_recover().sessions.len() } diff --git a/vibecli/vibecli-cli/src/serve.rs b/vibecli/vibecli-cli/src/serve.rs index 45cc56f09..7ca5e16d1 100644 --- a/vibecli/vibecli-cli/src/serve.rs +++ b/vibecli/vibecli-cli/src/serve.rs @@ -6725,6 +6725,74 @@ async fn v1_resume_get(Path(handle): Path<String>) -> (StatusCode, Json<serde_js helper_outcome_to_response(out) } +// ── Ghost text — /v1/ghost/complete ──────────────────────────────────────── +// +// Explicit-trigger inline completion for editor clients that speak HTTP rather +// than Tauri (the VS Code extension). One request per user gesture. +// +// The daemon cannot verify that a request was user-triggered — the gate lives +// in each client's inline-completion provider, which returns early for the +// editor's *automatic* trigger kind. This route deliberately has no session, +// no edit-history accumulator, and no debounce state, so there is nothing here +// that a keystroke loop could drive cheaply. + +#[derive(Debug, Deserialize)] +struct GhostCompleteRequest { + file_path: String, + language: String, + /// Text before the cursor, already windowed by the client. + prefix: String, + /// Text after the cursor, already windowed by the client. + #[serde(default)] + suffix: String, + #[serde(default)] + provider: Option<String>, + #[serde(default)] + model: Option<String>, +} + +async fn v1_ghost_complete_post( + State(state): State<ServeState>, + Json(req): Json<GhostCompleteRequest>, +) -> (StatusCode, Json<serde_json::Value>) { + if req.prefix.trim().is_empty() && req.suffix.trim().is_empty() { + return ( + StatusCode::BAD_REQUEST, + Json(serde_json::json!({ + "error": "prefix and suffix are both empty — nothing to complete" + })), + ); + } + + let provider = chat_provider_for( + &state.provider, + req.provider.as_deref(), + req.model.as_deref(), + ); + + let project_memory = crate::memory::ProjectMemory::load(&state.workspace_root).combined(); + + let request = vibe_ai::ghost::GhostRequest { + file_path: req.file_path, + language: req.language, + prefix: req.prefix, + suffix: req.suffix, + project_memory, + }; + + match vibe_ai::ghost::generate(provider, request).await { + Ok(res) => ( + StatusCode::OK, + Json(serde_json::json!({ + "completion": res.completion, + "model_name": res.model_name, + "truncated": res.truncated, + })), + ), + Err(e) => internal_error("ghost.generate", &e), + } +} + // ── Recap & Resume — D1.1 /v1/diffcomplete/chains autosave route ─────────── // // Persistence is *append-on-event* only. The modal posts here when a @@ -7972,6 +8040,8 @@ pub(crate) fn build_router(state: ServeState, port: u16) -> Router { // Writes happen only // on discrete user-driven events posted by the modal. .route("/v1/diffcomplete/chains", post(v1_diffcomplete_chains_post)) + // Ghost text — explicit-trigger inline completion (VS Code extension). + .route("/v1/ghost/complete", post(v1_ghost_complete_post)) // Mobile Gateway — machine registration & dispatch (iOS/Android remote management) .route("/mobile/machines", get(mobile_list_machines)) .route("/mobile/machines", post(mobile_register_machine)) @@ -12198,6 +12268,51 @@ mod tests { // ── Auth: unauthenticated requests to protected routes → 401 ── + // ── /v1/ghost/complete ───────────────────────────────────────── + // + // Stops short of a real model call — that needs a configured provider + // a test machine cannot assume. What is tested is everything the + // handler decides *before* dispatching: auth and empty-window + // rejection. + + #[tokio::test] + async fn ghost_complete_without_auth_returns_401() { + let (app, _tmp) = test_app("secret-token"); + let req = Request::builder() + .method("POST") + .uri("/v1/ghost/complete") + .header("content-type", "application/json") + .body(Body::from( + r#"{"file_path":"a.rs","language":"rust","prefix":"fn f() {","suffix":"}"}"#, + )) + .unwrap(); + let resp = app.oneshot(req).await.unwrap(); + assert_eq!( + resp.status(), + StatusCode::UNAUTHORIZED, + "ghost completion is not in the public route list" + ); + } + + #[tokio::test] + async fn ghost_complete_rejects_an_empty_window() { + // Both sides blank means there is no cursor context at all; that is + // a client bug, and answering it would bill a model call for a + // prompt with nothing in it. + let (app, _tmp) = test_app("secret-token"); + let req = Request::builder() + .method("POST") + .uri("/v1/ghost/complete") + .header("authorization", "Bearer secret-token") + .header("content-type", "application/json") + .body(Body::from( + r#"{"file_path":"a.rs","language":"rust","prefix":" ","suffix":""}"#, + )) + .unwrap(); + let resp = app.oneshot(req).await.unwrap(); + assert_eq!(resp.status(), StatusCode::BAD_REQUEST); + } + // ── /voice/transcribe + /voice/status ────────────────────────── // // These stop short of running a real engine: transcription needs either diff --git a/vibecoder/crates/vibe-ai/src/ghost.rs b/vibecoder/crates/vibe-ai/src/ghost.rs new file mode 100644 index 000000000..6e6e6cc51 --- /dev/null +++ b/vibecoder/crates/vibe-ai/src/ghost.rs @@ -0,0 +1,388 @@ +//! Explicit-trigger inline completion ("ghost text"). +//! +//! # Why this module is not the surface that was removed +//! +//! Commit `5a7eef7c` deleted the previous ghost-text path (`SupercompleteEngine` +//! + `request_inline_completion` + `predict_next_edit`) after an internal patent +//! audit flagged it HIGH. That surface was **keystroke-driven**: an edit-history +//! ring buffer fed a debounced FIM request on every pause in typing, and the +//! model's output was inserted inline on a single keypress. +//! +//! This module deliberately keeps the useful half and drops the flagged half: +//! +//! - **Trigger**: explicit chord only. The hosts gate on the editor's own +//! "explicit" trigger kind (`InlineCompletionTriggerKind::Explicit` in +//! Monaco, `::Invoke` in VS Code) and return nothing for the automatic kind. +//! There is no debounce timer and no on-type path to remove, because none +//! is ever installed. +//! - **Hidden state**: none. The request carries the prefix/suffix window +//! around the cursor and nothing else — no edit-event history, no +//! accepted/rejected telemetry, no automatic embedding retrieval. What the +//! model sees is what is on screen. +//! - **Output**: a plain continuation for the current cursor position, capped +//! to a bounded number of lines. +//! +//! The one thing shared with the removed surface is inline presentation and +//! Tab-to-accept, which the host provides natively. +//! +//! [`crate::diffcomplete`] remains the multi-line, review-before-apply surface; +//! this one is for the short continuation where opening a modal is too heavy. + +use crate::provider::{AIProvider, Message, MessageRole}; +use anyhow::Result; +use serde::{Deserialize, Serialize}; +use std::sync::Arc; + +/// How many lines of continuation we ask for, and enforce on the way out. +/// +/// A cap is part of the design, not a performance tweak: an unbounded +/// continuation is a code generator, and this surface is deliberately a +/// completion of the line(s) under the cursor. +pub const MAX_COMPLETION_LINES: usize = 12; + +/// A single explicit-trigger completion request. +/// +/// `prefix` is the text before the cursor and `suffix` the text after it, each +/// already windowed by the host. Splitting at the cursor rather than sending +/// the whole file is what lets the model complete *at* a point instead of +/// rewriting a region. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct GhostRequest { + pub file_path: String, + pub language: String, + /// Text before the cursor (windowed by the host). + pub prefix: String, + /// Text after the cursor (windowed by the host). + pub suffix: String, + /// Author-authored project memory, same audit-restricted source as + /// diffcomplete's. **MUST NOT** carry auto-extracted state. + #[serde(default)] + pub project_memory: Option<String>, +} + +/// A completion, ready for the host to render as ghost text at the cursor. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct GhostResponse { + /// Text to insert verbatim at the cursor. Never empty on `Ok`. + pub completion: String, + pub model_name: String, + /// True when [`MAX_COMPLETION_LINES`] clipped the model's output. The host + /// surfaces this rather than pretending the suggestion was complete. + pub truncated: bool, +} + +const SYSTEM_PROMPT: &str = "You are a code completion engine. The user gives \ +you a file split at the cursor into a PREFIX and a SUFFIX. Output the text that \ +belongs at the cursor, so that PREFIX + your output + SUFFIX is valid code.\n\ +\n\ +Rules:\n\ +- Output ONLY the insertion text. No prose, no explanation, no commentary.\n\ +- Do NOT repeat any part of the PREFIX or the SUFFIX.\n\ +- Do NOT wrap the output in a markdown code fence.\n\ +- Continue the prefix exactly where it stops, mid-token if that is where the \ +cursor is.\n\ +- Match the surrounding indentation, naming style, and language idiom.\n\ +- Keep it short: complete the current statement, expression, or block. Stop \ +when a reasonable suggestion ends.\n\ +- If nothing sensible belongs at the cursor, output nothing at all."; + +/// Build the message list for a request. +/// +/// Mirrors [`crate::diffcomplete::build_messages`]: canonical system prompt +/// first, then project memory as its own system message when present, then the +/// user message. Memory is *context*, never folded into the instruction. +pub fn build_messages(request: &GhostRequest) -> Vec<Message> { + let memory = request + .project_memory + .as_deref() + .map(str::trim) + .filter(|s| !s.is_empty()); + + let mut messages = Vec::with_capacity(if memory.is_some() { 3 } else { 2 }); + messages.push(Message { + role: MessageRole::System, + content: SYSTEM_PROMPT.to_string(), + }); + if let Some(mem) = memory { + messages.push(Message { + role: MessageRole::System, + content: format!( + "Project memory (author-authored, from VIBECLI.md / AGENTS.md / CLAUDE.md):\n\n{mem}" + ), + }); + } + messages.push(Message { + role: MessageRole::User, + content: build_user_prompt(request), + }); + messages +} + +/// Build the user message. +pub fn build_user_prompt(req: &GhostRequest) -> String { + let mut out = String::with_capacity(req.prefix.len() + req.suffix.len() + 256); + out.push_str("File: "); + out.push_str(&req.file_path); + out.push_str("\nLanguage: "); + out.push_str(&req.language); + out.push_str("\n\n=== PREFIX (text before the cursor) ===\n"); + out.push_str(&req.prefix); + out.push_str("\n=== CURSOR ===\n=== SUFFIX (text after the cursor) ===\n"); + out.push_str(&req.suffix); + out.push_str("\n\nOutput the insertion text for the cursor position:"); + out +} + +/// Strip the wrappers models add despite being told not to, and enforce the +/// line cap. +/// +/// Returns `(completion, truncated)`. An empty completion means the model +/// declined — that is a valid answer here ("nothing belongs at the cursor"), +/// and the caller reports it as such rather than as an error. +/// +/// Trailing whitespace is trimmed but **leading whitespace is preserved**: at a +/// cursor sitting at column 0 of an indented block, the indentation *is* the +/// first thing that belongs at the cursor. +pub fn sanitize_completion(raw: &str) -> (String, bool) { + let unfenced = strip_code_fence(raw); + let mut lines: Vec<&str> = unfenced.lines().collect(); + + // Drop trailing blank lines before counting, so a model that pads its + // answer doesn't burn the line budget or trip the truncation flag. + while lines.last().is_some_and(|l| l.trim().is_empty()) { + lines.pop(); + } + + let truncated = lines.len() > MAX_COMPLETION_LINES; + if truncated { + lines.truncate(MAX_COMPLETION_LINES); + } + + let joined = lines.join("\n"); + // `trim_end` only — see the doc comment on leading whitespace. + (joined.trim_end().to_string(), truncated) +} + +/// Remove a single wrapping ``` fence if the whole response is one. +/// +/// Only strips when the response *starts* with a fence, so a completion that +/// legitimately contains a fence (writing a doc comment, say) is untouched. +fn strip_code_fence(raw: &str) -> &str { + let trimmed = raw.trim_matches('\n'); + let Some(rest) = trimmed.strip_prefix("```") else { + return raw; + }; + // Drop the info string (```rust) on the opening fence. + let after_open = match rest.find('\n') { + Some(nl) => &rest[nl + 1..], + // A fence with no newline has no body. + None => return "", + }; + after_open + .rfind("```") + .map_or(after_open, |close| &after_open[..close]) +} + +/// Generate a completion for the cursor position using the supplied provider. +/// +/// Callers must have established that the user explicitly asked for this — the +/// hosts do that by gating on the editor's explicit trigger kind. Nothing in +/// this function can tell an explicit request from an automatic one, so the +/// gate belongs at the edge and must not be relaxed there. +pub async fn generate(provider: Arc<dyn AIProvider>, request: GhostRequest) -> Result<GhostResponse> { + let provider_name = provider.name().to_string(); + + tracing::debug!( + target: "vibecody::ghost", + provider = %provider_name, + language = %request.language, + file_path = %request.file_path, + prefix_len = request.prefix.len(), + suffix_len = request.suffix.len(), + "ghost completion requested" + ); + + if !provider.is_available().await { + tracing::warn!( + target: "vibecody::ghost", + provider = %provider_name, + "ghost provider unavailable" + ); + anyhow::bail!("Provider {} is not available", provider_name); + } + + let messages = build_messages(&request); + + let raw = provider.chat(&messages, None).await.map_err(|e| { + tracing::warn!( + target: "vibecody::ghost", + provider = %provider_name, + error = %e, + "ghost provider chat call failed" + ); + e + })?; + + let (completion, truncated) = sanitize_completion(&raw); + + tracing::info!( + target: "vibecody::ghost", + provider = %provider_name, + completion_len = completion.len(), + truncated, + "ghost completion generated" + ); + + Ok(GhostResponse { + completion, + model_name: provider_name, + truncated, + }) +} + +#[cfg(test)] +mod tests { + use super::*; + + fn request_stub() -> GhostRequest { + GhostRequest { + file_path: "src/lib.rs".to_string(), + language: "rust".to_string(), + prefix: "fn add(a: i32, b: i32) -> i32 {\n ".to_string(), + suffix: "\n}\n".to_string(), + project_memory: None, + } + } + + // ── Prompt construction ────────────────────────────────────────────── + + #[test] + fn build_messages_emits_only_system_and_user_when_memory_absent() { + let msgs = build_messages(&request_stub()); + assert_eq!(msgs.len(), 2, "no memory → exactly 2 messages"); + assert_eq!(msgs[0].role, MessageRole::System); + assert_eq!(msgs[1].role, MessageRole::User); + } + + #[test] + fn build_messages_inserts_memory_as_second_system_message() { + let req = GhostRequest { + project_memory: Some("Always use anyhow::Result.".to_string()), + ..request_stub() + }; + let msgs = build_messages(&req); + assert_eq!(msgs.len(), 3); + assert_eq!(msgs[1].role, MessageRole::System); + assert!(msgs[1].content.contains("Always use anyhow::Result.")); + assert_eq!(msgs[2].role, MessageRole::User); + assert!( + !msgs[2].content.contains("Always use anyhow::Result."), + "memory is context, not instruction — it must not leak into the user message" + ); + } + + #[test] + fn whitespace_only_memory_is_treated_as_absent() { + let req = GhostRequest { + project_memory: Some(" \n ".to_string()), + ..request_stub() + }; + assert_eq!(build_messages(&req).len(), 2); + } + + #[test] + fn user_prompt_splits_at_the_cursor() { + let prompt = build_user_prompt(&request_stub()); + let cursor = prompt.find("=== CURSOR ===").expect("cursor marker present"); + let prefix_at = prompt.find("fn add(a: i32").expect("prefix present"); + let suffix_at = prompt.rfind("\n}\n").expect("suffix present"); + assert!(prefix_at < cursor, "prefix must precede the cursor marker"); + assert!(suffix_at > cursor, "suffix must follow the cursor marker"); + } + + // ── Sanitising ─────────────────────────────────────────────────────── + + #[test] + fn plain_completion_passes_through() { + let (out, truncated) = sanitize_completion("a + b"); + assert_eq!(out, "a + b"); + assert!(!truncated); + } + + #[test] + fn leading_indentation_is_preserved() { + // The cursor sits at column 0 of an indented block; the indentation is + // part of what belongs at the cursor. Trimming it would left-align the + // suggestion against its neighbours. + let (out, _) = sanitize_completion(" let x = 1;\n x + 1"); + assert_eq!(out, " let x = 1;\n x + 1"); + } + + #[test] + fn fenced_response_is_unwrapped() { + let (out, _) = sanitize_completion("```rust\na + b\n```"); + assert_eq!(out, "a + b"); + } + + #[test] + fn fenced_response_without_info_string_is_unwrapped() { + let (out, _) = sanitize_completion("```\na + b\n```"); + assert_eq!(out, "a + b"); + } + + #[test] + fn interior_fence_is_left_alone() { + // A completion that writes a doc comment containing a fence must not + // be mangled — only a fence wrapping the *whole* response is stripped. + let raw = "/// ```\n/// let x = 1;\n/// ```\npub fn f() {}"; + let (out, _) = sanitize_completion(raw); + assert_eq!(out, raw); + } + + #[test] + fn declining_to_complete_yields_empty_not_error() { + let (out, truncated) = sanitize_completion(" \n\n "); + assert!(out.is_empty(), "an empty answer is a valid 'nothing fits here'"); + assert!(!truncated); + } + + #[test] + fn output_is_capped_and_flagged() { + let long = (0..MAX_COMPLETION_LINES + 5) + .map(|i| format!("line {i}")) + .collect::<Vec<_>>() + .join("\n"); + let (out, truncated) = sanitize_completion(&long); + assert!(truncated, "over-long output must report truncation"); + assert_eq!(out.lines().count(), MAX_COMPLETION_LINES); + } + + #[test] + fn trailing_blank_lines_do_not_trip_truncation() { + // Exactly at the cap plus padding: the padding is dropped before + // counting, so this is not a truncation. + let padded = format!( + "{}\n\n\n", + (0..MAX_COMPLETION_LINES) + .map(|i| format!("line {i}")) + .collect::<Vec<_>>() + .join("\n") + ); + let (out, truncated) = sanitize_completion(&padded); + assert!(!truncated); + assert_eq!(out.lines().count(), MAX_COMPLETION_LINES); + } + + #[test] + fn unterminated_fence_still_unwraps() { + // Streaming responses get cut off mid-fence; the body is still usable. + let (out, _) = sanitize_completion("```rust\na + b"); + assert_eq!(out, "a + b"); + } + + #[test] + fn bare_fence_yields_empty() { + let (out, _) = sanitize_completion("```"); + assert!(out.is_empty()); + } +} diff --git a/vibecoder/crates/vibe-ai/src/lib.rs b/vibecoder/crates/vibe-ai/src/lib.rs index 19adb1e55..011effccf 100644 --- a/vibecoder/crates/vibe-ai/src/lib.rs +++ b/vibecoder/crates/vibe-ai/src/lib.rs @@ -7,6 +7,7 @@ pub mod catalog; pub mod chat; pub mod config; pub mod diffcomplete; +pub mod ghost; pub mod hooks; pub mod mcp; pub mod multi_agent; diff --git a/vibecoder/crates/vibe-core/Cargo.toml b/vibecoder/crates/vibe-core/Cargo.toml index ad58a32be..3a7193232 100644 --- a/vibecoder/crates/vibe-core/Cargo.toml +++ b/vibecoder/crates/vibe-core/Cargo.toml @@ -29,7 +29,7 @@ regex = "1" portable-pty = "0.9" # Diff -similar = { version = "2.6", features = ["inline"] } +similar = { version = "3.1", features = ["inline"] } # Crypto-safe random (temp file names, etc.) rand = "0.10" diff --git a/vibecoder/package-lock.json b/vibecoder/package-lock.json index 63c07114c..bab25fd86 100644 --- a/vibecoder/package-lock.json +++ b/vibecoder/package-lock.json @@ -1,12 +1,12 @@ { "name": "tauri-app", - "version": "0.5.7", + "version": "0.5.8", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "tauri-app", - "version": "0.5.7", + "version": "0.5.8", "hasInstallScript": true, "dependencies": { "@dagrejs/dagre": "^3.1.0", @@ -17,7 +17,7 @@ "@xyflow/react": "^12.11.2", "dompurify": "^3.4.13", "fuse.js": "^7.5.0", - "lucide-react": "^1.28.0", + "lucide-react": "^1.29.0", "react": "^19.2.8", "react-dom": "^19.2.8", "react-markdown": "^10.1.0", @@ -25,8 +25,8 @@ "xterm": "^5.3.0", "xterm-addon-fit": "^0.8.0", "y-monaco": "^0.1.6", - "y-websocket": "^3.0.0", - "yjs": "^13.6.31" + "y-websocket": "^3.1.0", + "yjs": "^13.6.32" }, "devDependencies": { "@eslint/js": "^10.0.1", @@ -43,12 +43,12 @@ "eslint": "^10.8.0", "eslint-plugin-no-unsanitized": "^4.1.2", "eslint-plugin-react-hooks": "^7.0.1", - "jsdom": "^29.0.0", - "monaco-editor": "^0.55.1", + "jsdom": "^30.0.1", + "monaco-editor": "^0.56.0", "patch-package": "^8.0.1", "typescript": "~6.0.3", "typescript-eslint": "^8.66.0", - "vite": "^8.2.0", + "vite": "^8.2.1", "vitest": "^4.1.10" } }, @@ -60,56 +60,58 @@ "license": "MIT" }, "node_modules/@asamuzakjp/css-color": { - "version": "5.1.11", - "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-5.1.11.tgz", - "integrity": "sha512-KVw6qIiCTUQhByfTd78h2yD1/00waTmm9uy/R7Ck/ctUyAPj+AEDLkQIdJW0T8+qGgj3j5bpNKK7Q3G+LedJWg==", + "version": "6.0.7", + "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-6.0.7.tgz", + "integrity": "sha512-vC/bk1Lz7Tn/EfU9/apOTBk80/8dyGyWMowPoV1tJ52muDGsDqt2HPT2klrFUiY60MQmQv9q8yIht15JnBgDGw==", "dev": true, "license": "MIT", "dependencies": { - "@asamuzakjp/generational-cache": "^1.0.1", - "@csstools/css-calc": "^3.2.0", - "@csstools/css-color-parser": "^4.1.0", + "@csstools/css-calc": "^3.3.0", + "@csstools/css-color-parser": "^4.1.10", "@csstools/css-parser-algorithms": "^4.0.0", - "@csstools/css-tokenizer": "^4.0.0" + "@csstools/css-tokenizer": "^4.0.0", + "lru-cache": "^11.5.2" }, "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + "node": "^22.13.0 || >=24.0.0" + } + }, + "node_modules/@asamuzakjp/css-color/node_modules/lru-cache": { + "version": "11.5.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.2.tgz", + "integrity": "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" } }, "node_modules/@asamuzakjp/dom-selector": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-7.1.1.tgz", - "integrity": "sha512-67RZDnYRc8H/8MLDgQCDE//zoqVFwajkepHZgmXrbwybzXOEwOWGPYGmALYl9J2DOLfFPPs6kKCqmbzV895hTQ==", + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-8.3.2.tgz", + "integrity": "sha512-93Z1N+BQNXysodoicpOIyNh2drHfz/CTf9nnT0FEx72GJcIiwgydD7tGAr78j41LsYn3hlRn+LdGPuBLn1Bl8Q==", "dev": true, "license": "MIT", "dependencies": { - "@asamuzakjp/generational-cache": "^1.0.1", - "@asamuzakjp/nwsapi": "^2.3.9", "bidi-js": "^1.0.3", "css-tree": "^3.2.1", - "is-potential-custom-element-name": "^1.0.1" + "is-potential-custom-element-name": "^1.0.1", + "lru-cache": "^11.5.2" }, "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + "node": "^22.13.0 || >=24.0.0" } }, - "node_modules/@asamuzakjp/generational-cache": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@asamuzakjp/generational-cache/-/generational-cache-1.0.1.tgz", - "integrity": "sha512-wajfB8KqzMCN2KGNFdLkReeHncd0AslUSrvHVvvYWuU8ghncRJoA50kT3zP9MVL0+9g4/67H+cdvBskj9THPzg==", + "node_modules/@asamuzakjp/dom-selector/node_modules/lru-cache": { + "version": "11.5.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.2.tgz", + "integrity": "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==", "dev": true, - "license": "MIT", + "license": "BlueOak-1.0.0", "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + "node": "20 || >=22" } }, - "node_modules/@asamuzakjp/nwsapi": { - "version": "2.3.9", - "resolved": "https://registry.npmjs.org/@asamuzakjp/nwsapi/-/nwsapi-2.3.9.tgz", - "integrity": "sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==", - "dev": true, - "license": "MIT" - }, "node_modules/@babel/code-frame": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", @@ -374,9 +376,9 @@ } }, "node_modules/@csstools/color-helpers": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-6.0.2.tgz", - "integrity": "sha512-LMGQLS9EuADloEFkcTBR3BwV/CGHV7zyDxVRtVDTwdI2Ca4it0CCVTT9wCkxSgokjE5Ho41hEPgb8OEUwoXr6Q==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-6.1.0.tgz", + "integrity": "sha512-064IFJdjTfUqnjpCVpMOdbr8FLQBhinbZj6yRv2An2E41O/pLEXqfFRWqGq/SxlE5PEUYTlvWsG2r8MswAVvkg==", "dev": true, "funding": [ { @@ -394,9 +396,9 @@ } }, "node_modules/@csstools/css-calc": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-3.2.1.tgz", - "integrity": "sha512-DtdHlgXh5ZkA43cwBcAm+huzgJiwx3ZTWVjBs94kwz2xKqSimDA3lBgCjphYgwgVUMWatSM0pDd8TILB1yrVVg==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-3.3.0.tgz", + "integrity": "sha512-c5ihYsPkdG6JCkU2zTMm4+k6r7RXuGxtWYhu5DHMIiF1FHzrfmHL5so11AoFpUv/tu61xfcmT4AmKoFfMPoqdQ==", "dev": true, "funding": [ { @@ -418,9 +420,9 @@ } }, "node_modules/@csstools/css-color-parser": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-4.1.1.tgz", - "integrity": "sha512-eZ5XOtyhK+mggRafYUWzA0tvaYOFgdY8AkgQiCJF9qNAePnUo/zmsqqYubBBb3sQ8uNUaSKTY9s9klfRaAXL0g==", + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-4.1.10.tgz", + "integrity": "sha512-UZhQLIUyJaaMepqehrCODwCg2KW25vFvLWBmqYFaPclYvvxzj/sG8LBOhBFCp11i9uE7t1EyS+RAoV9tztPFyw==", "dev": true, "funding": [ { @@ -434,8 +436,8 @@ ], "license": "MIT", "dependencies": { - "@csstools/color-helpers": "^6.0.2", - "@csstools/css-calc": "^3.2.1" + "@csstools/color-helpers": "^6.1.0", + "@csstools/css-calc": "^3.3.0" }, "engines": { "node": ">=20.19.0" @@ -469,9 +471,9 @@ } }, "node_modules/@csstools/css-syntax-patches-for-csstree": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.1.4.tgz", - "integrity": "sha512-wgsqt92b7C7tQhIdPNxj0n9zuUbQlvAuI1exyzeNrOKOi62SD7ren8zqszmpVREjAOqg8cD2FqYhQfAuKjk4sw==", + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.1.7.tgz", + "integrity": "sha512-fQ+05118eQS1cofO3aJpB5efgpBZMvIzwr/sbC8kDLVA5XLG8q1kJV5yzrUAI1f7lvhPnm8fgIjzFB8/O/5Dig==", "dev": true, "funding": [ { @@ -1636,92 +1638,6 @@ "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", "license": "MIT" }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.66.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.66.0.tgz", - "integrity": "sha512-p088eaGrzYz1s+7cov0aMOCkNGTJlVxF4jgubf28c8L0Cv9Rloj8YBHnv4hXLq6IIEE1AsjNWavO+k+8kP2Y0A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.66.0", - "@typescript-eslint/type-utils": "8.66.0", - "@typescript-eslint/utils": "8.66.0", - "@typescript-eslint/visitor-keys": "8.66.0", - "ignore": "^7.0.5", - "natural-compare": "^1.4.0", - "ts-api-utils": "^2.5.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^8.66.0", - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.6.tgz", - "integrity": "sha512-BAg6QkE8W+TuQLrrw0Ugr7HegXduRuuj8/ti2kSOc+jz1dmx8/WNcjr6XGnq5YpDWxFwwaavqD0+jIUOKelTsw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "8.66.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.66.0.tgz", - "integrity": "sha512-X6ypGChaWYk6PBtUg2BwuTZEFFcHJAtGTVJ9/lCTOufhZ4i9fNolQNnktq+kkMCwMj7V8Svsq7+TxSDslmhE0g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/scope-manager": "8.66.0", - "@typescript-eslint/types": "8.66.0", - "@typescript-eslint/typescript-estree": "8.66.0", - "@typescript-eslint/visitor-keys": "8.66.0", - "debug": "^4.4.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/project-service": { - "version": "8.66.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.66.0.tgz", - "integrity": "sha512-7MthGPTt4BP69lSryqpqq8HQqxuzynssckL/jyDyk3+TNMQ3y2jFWkptCrktWvBrP+EH787Nl5N5Qpw7WZg+5g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.66.0", - "@typescript-eslint/types": "^8.66.0", - "debug": "^4.4.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.1.0" - } - }, "node_modules/@typescript-eslint/scope-manager": { "version": "8.66.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.66.0.tgz", @@ -1740,48 +1656,6 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.66.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.66.0.tgz", - "integrity": "sha512-9D5gLYZG4rOjcoag8MQ/fWI8WqA9wcPDyOGyWtWFhvM1lHRbliqUSPIY5J3zqCU1tvSwzXxnnjhQhz5Ne7mJ4g==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "8.66.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.66.0.tgz", - "integrity": "sha512-LG2dWfjZQQp0ADtAu/EWJVayefGL2UEZ3CDeI44D9v3rXB/WYUqE/jpO28KrEKul5AySrmI+Zh1v6v+xW2U9+g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.66.0", - "@typescript-eslint/typescript-estree": "8.66.0", - "@typescript-eslint/utils": "8.66.0", - "debug": "^4.4.3", - "ts-api-utils": "^2.5.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.1.0" - } - }, "node_modules/@typescript-eslint/types": { "version": "8.66.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.66.0.tgz", @@ -1796,71 +1670,6 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.66.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.66.0.tgz", - "integrity": "sha512-8/x4INiiQb10jGgXYD7116/zQ+OL84ZIFn0za68wwFHCanT/VLbBEroWht8RV8fn0/ZCAoazHLQgwUC0UQcDfg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/project-service": "8.66.0", - "@typescript-eslint/tsconfig-utils": "8.66.0", - "@typescript-eslint/types": "8.66.0", - "@typescript-eslint/visitor-keys": "8.66.0", - "debug": "^4.4.3", - "minimatch": "^10.2.2", - "semver": "^7.7.3", - "tinyglobby": "^0.2.15", - "ts-api-utils": "^2.5.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.8.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", - "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "8.66.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.66.0.tgz", - "integrity": "sha512-jasearZPolBw5NJNYGMwxzHMF83niVWmMU1VdHzG1CyfI2VS7f7nZltnKtHcg20hW+7Uo5GfK4MeDPoU3qI8EA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.66.0", - "@typescript-eslint/types": "8.66.0", - "@typescript-eslint/typescript-estree": "8.66.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.1.0" - } - }, "node_modules/@typescript-eslint/visitor-keys": { "version": "8.66.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.66.0.tgz", @@ -3611,39 +3420,39 @@ "license": "MIT" }, "node_modules/jsdom": { - "version": "29.1.1", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-29.1.1.tgz", - "integrity": "sha512-ECi4Fi2f7BdJtUKTflYRTiaMxIB0O6zfR1fX0GXpUrf6flp8QIYn1UT20YQqdSOfk2dfkCwS8LAFoJDEppNK5Q==", + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-30.0.1.tgz", + "integrity": "sha512-52v7mUVUfNQVYYqE1lcdaymWL0njO7lTLUog6ZvW2U5KsbiLk/GnZlVJ+qx0xfNJZ6Gn+KSpPNE52vurbxZwrA==", "dev": true, "license": "MIT", "dependencies": { - "@asamuzakjp/css-color": "^5.1.11", - "@asamuzakjp/dom-selector": "^7.1.1", + "@asamuzakjp/css-color": "^6.0.5", + "@asamuzakjp/dom-selector": "^8.3.0", "@bramus/specificity": "^2.4.2", - "@csstools/css-syntax-patches-for-csstree": "^1.1.3", - "@exodus/bytes": "^1.15.0", + "@csstools/css-syntax-patches-for-csstree": "^1.1.7", + "@exodus/bytes": "^1.15.1", "css-tree": "^3.2.1", "data-urls": "^7.0.0", "decimal.js": "^10.6.0", "html-encoding-sniffer": "^6.0.0", "is-potential-custom-element-name": "^1.0.1", - "lru-cache": "^11.3.5", + "lru-cache": "^11.5.2", "parse5": "^8.0.1", "saxes": "^6.0.0", "symbol-tree": "^3.2.4", - "tough-cookie": "^6.0.1", - "undici": "^7.25.0", + "tough-cookie": "^6.0.2", + "undici": "^8.9.0", "w3c-xmlserializer": "^5.0.0", "webidl-conversions": "^8.0.1", "whatwg-mimetype": "^5.0.0", - "whatwg-url": "^16.0.1", + "whatwg-url": "^17.1.0", "xml-name-validator": "^5.0.0" }, "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24.0.0" + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" }, "peerDependencies": { - "canvas": "^3.0.0" + "canvas": "^3.2.3" }, "peerDependenciesMeta": { "canvas": { @@ -3652,15 +3461,30 @@ } }, "node_modules/jsdom/node_modules/lru-cache": { - "version": "11.5.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.1.tgz", - "integrity": "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==", + "version": "11.5.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.2.tgz", + "integrity": "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==", "dev": true, "license": "BlueOak-1.0.0", "engines": { "node": "20 || >=22" } }, + "node_modules/jsdom/node_modules/whatwg-url": { + "version": "17.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-17.1.0.tgz", + "integrity": "sha512-3GeworPmc2ZfEEHP7lEbUfBX/L75wdEsi0rLNhXcXxnoN5jyq0SL5gCy06SGW2cyTIZdTvWIDQNQoza++vKeaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@exodus/bytes": "^1.15.1", + "tr46": "^6.0.0", + "webidl-conversions": "^8.0.1" + }, + "engines": { + "node": "^22.14.0 || >=24.0.0" + } + }, "node_modules/jsesc": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", @@ -4116,9 +3940,9 @@ } }, "node_modules/lucide-react": { - "version": "1.28.0", - "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-1.28.0.tgz", - "integrity": "sha512-fARAFJULsGuDDydjp6+6blekG/sBIM29TerzLjc9bQUKAcEfrSc4ZQKb25KRz4OMKd87cZTb5dgq0w/T6KufVg==", + "version": "1.31.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-1.31.0.tgz", + "integrity": "sha512-G8u2eEtoHUnUa9f8lbvqDhCiORMnYLdUEo06EEG9MQvHQrInKcX3Pa2TH39MM5qyzRcWETxB0+aOwAPI1g1kEg==", "license": "ISC", "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" @@ -5079,12 +4903,12 @@ } }, "node_modules/monaco-editor": { - "version": "0.55.1", - "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.55.1.tgz", - "integrity": "sha512-jz4x+TJNFHwHtwuV9vA9rMujcZRb0CEilTEwG2rRSpe/A7Jdkuj8xPKttCgOh+v/lkHy7HsZ64oj+q3xoAFl9A==", + "version": "0.56.0", + "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.56.0.tgz", + "integrity": "sha512-sXboRm3BeBeLm938eaiyLMe0OxzfXIlZvbv4ir/jVgQy1zDhWjgmny0WoN45fuDKhCCQsYMbBJrv/A6jd8aCUg==", "license": "MIT", "dependencies": { - "dompurify": "3.2.7", + "dompurify": "3.4.8", "marked": "14.0.0" } }, @@ -5911,22 +5735,22 @@ } }, "node_modules/tldts": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.4.0.tgz", - "integrity": "sha512-yHBe+zVfzNZ3QfTPW/Z6KK1G2t340gFjMHqI/4KKSt/abzYydzuCnpqdaF5gCCABby+9Yfbj59oR5F2Fd5CBzg==", + "version": "7.4.10", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.4.10.tgz", + "integrity": "sha512-GgouD1B+sWwvkaEq8vXC15DjQitxbvs12oIXELpconwm+Tg3zfcEv4jgzq3vtKverDXsg3VI8aRgNL2Nra0Iog==", "dev": true, "license": "MIT", "dependencies": { - "tldts-core": "^7.4.0" + "tldts-core": "^7.4.10" }, "bin": { "tldts": "bin/cli.js" } }, "node_modules/tldts-core": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.4.0.tgz", - "integrity": "sha512-/mb9kRld+x1sIMXxWNOAp5m6C+D4GrAORWlJkOJ5dElvxdN1eutz/o7qHLp9gFvDF4Y3/L2xeScoxz6AbEo8rQ==", + "version": "7.4.10", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.4.10.tgz", + "integrity": "sha512-KnQjp53ZekKgm/r3l+u8kJGGzYgrWdP8+Mql7a4vijh2WE0IrZWspQj/TpTxDho/YxO+AnOZnIjQcCD+q6iJsw==", "dev": true, "license": "MIT" }, @@ -5954,9 +5778,9 @@ } }, "node_modules/tough-cookie": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-6.0.1.tgz", - "integrity": "sha512-LktZQb3IeoUWB9lqR5EWTHgW/VTITCXg4D21M+lvybRVdylLrRMnqaIONLVb5mav8vM19m44HIcGq4qASeu2Qw==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-6.0.2.tgz", + "integrity": "sha512-exgYmnmL/sJpR3upZfXG5PoatXQii55xAiXGXzY+sROLZ/Y+SLcp9PgJNI9Vz37HpQ74WvDcLT8eqm+kV3FzrA==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -6063,14 +5887,207 @@ "typescript": ">=4.8.4 <6.1.0" } }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.66.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.66.0.tgz", + "integrity": "sha512-p088eaGrzYz1s+7cov0aMOCkNGTJlVxF4jgubf28c8L0Cv9Rloj8YBHnv4hXLq6IIEE1AsjNWavO+k+8kP2Y0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.66.0", + "@typescript-eslint/type-utils": "8.66.0", + "@typescript-eslint/utils": "8.66.0", + "@typescript-eslint/visitor-keys": "8.66.0", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.66.0", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils": { + "version": "8.66.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.66.0.tgz", + "integrity": "sha512-LG2dWfjZQQp0ADtAu/EWJVayefGL2UEZ3CDeI44D9v3rXB/WYUqE/jpO28KrEKul5AySrmI+Zh1v6v+xW2U9+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.66.0", + "@typescript-eslint/typescript-estree": "8.66.0", + "@typescript-eslint/utils": "8.66.0", + "debug": "^4.4.3", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/parser": { + "version": "8.66.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.66.0.tgz", + "integrity": "sha512-X6ypGChaWYk6PBtUg2BwuTZEFFcHJAtGTVJ9/lCTOufhZ4i9fNolQNnktq+kkMCwMj7V8Svsq7+TxSDslmhE0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.66.0", + "@typescript-eslint/types": "8.66.0", + "@typescript-eslint/typescript-estree": "8.66.0", + "@typescript-eslint/visitor-keys": "8.66.0", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/typescript-estree": { + "version": "8.66.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.66.0.tgz", + "integrity": "sha512-8/x4INiiQb10jGgXYD7116/zQ+OL84ZIFn0za68wwFHCanT/VLbBEroWht8RV8fn0/ZCAoazHLQgwUC0UQcDfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.66.0", + "@typescript-eslint/tsconfig-utils": "8.66.0", + "@typescript-eslint/types": "8.66.0", + "@typescript-eslint/visitor-keys": "8.66.0", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/project-service": { + "version": "8.66.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.66.0.tgz", + "integrity": "sha512-7MthGPTt4BP69lSryqpqq8HQqxuzynssckL/jyDyk3+TNMQ3y2jFWkptCrktWvBrP+EH787Nl5N5Qpw7WZg+5g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.66.0", + "@typescript-eslint/types": "^8.66.0", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.66.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.66.0.tgz", + "integrity": "sha512-9D5gLYZG4rOjcoag8MQ/fWI8WqA9wcPDyOGyWtWFhvM1lHRbliqUSPIY5J3zqCU1tvSwzXxnnjhQhz5Ne7mJ4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/utils": { + "version": "8.66.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.66.0.tgz", + "integrity": "sha512-jasearZPolBw5NJNYGMwxzHMF83niVWmMU1VdHzG1CyfI2VS7f7nZltnKtHcg20hW+7Uo5GfK4MeDPoU3qI8EA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.66.0", + "@typescript-eslint/types": "8.66.0", + "@typescript-eslint/typescript-estree": "8.66.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/typescript-eslint/node_modules/ignore": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.6.tgz", + "integrity": "sha512-BAg6QkE8W+TuQLrrw0Ugr7HegXduRuuj8/ti2kSOc+jz1dmx8/WNcjr6XGnq5YpDWxFwwaavqD0+jIUOKelTsw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/typescript-eslint/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/undici": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-7.29.0.tgz", - "integrity": "sha512-IDxfleLmmbSskfWSUATiN1nfn2rDuvnMOqb5CWR92iIfojA0Ud+ulOAAEQ57LPr9rWmsreUyf5lwyao+7GNNVw==", + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-8.10.0.tgz", + "integrity": "sha512-HvltHd7avK13QIw/oLe4qoOLyoVSoafqJ2jYOrtMRBkbYT31eiBQ8O0ehRKZiEZCMEyLFQNIADpgCWC5fALvYQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=20.18.1" + "node": ">=22.19.0" } }, "node_modules/undici-types": { @@ -6256,16 +6273,16 @@ } }, "node_modules/vite": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/vite/-/vite-8.2.0.tgz", - "integrity": "sha512-pn+CFpM0lwDeKwmOq1ZaBK/9sjorZcgqxki6MbY/jPEVd9vichIlmlD4HmQ5wdP5EgqQCFRaACBxMC7uEGc6lQ==", + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.2.1.tgz", + "integrity": "sha512-EU/eS7BH3XROHh2YnBefjM6DBKA6ZeMZEYQbj7NLWg5wHYlhB8B/Mayd5XsgWq+NFYccDOTemRpdETWR6Ka/lw==", "dev": true, "license": "MIT", "dependencies": { "lightningcss": "^1.33.0", "picomatch": "^4.0.5", - "postcss": "^8.5.23", - "rolldown": "~1.2.0", + "postcss": "^8.5.25", + "rolldown": "~1.2.1", "tinyglobby": "^0.2.17" }, "bin": { @@ -6627,9 +6644,9 @@ } }, "node_modules/y-websocket": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/y-websocket/-/y-websocket-3.0.0.tgz", - "integrity": "sha512-mUHy7AzkOZ834T/7piqtlA8Yk6AchqKqcrCXjKW8J1w2lPtRDjz8W5/CvXz9higKAHgKRKqpI3T33YkRFLkPtg==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/y-websocket/-/y-websocket-3.1.0.tgz", + "integrity": "sha512-ZNzwH84Ysxv7zjpFNZHjTJvrBZgcAqMljTe+6zrWciAML9LQ18aVylyPNH9faxCXqEOV8I0JY4TGtrIHFX+Xwg==", "license": "MIT", "dependencies": { "lib0": "^0.2.102", @@ -6671,9 +6688,9 @@ } }, "node_modules/yjs": { - "version": "13.6.31", - "resolved": "https://registry.npmjs.org/yjs/-/yjs-13.6.31.tgz", - "integrity": "sha512-Eq+5BRfbeGyqGVrTJL3bEcr8gKkxPuyuoHmAwpk52fDb8kOVMrfVSTRPd6yiGgX5Fskb96qCRjzjbRjrL4YEnw==", + "version": "13.6.32", + "resolved": "https://registry.npmjs.org/yjs/-/yjs-13.6.32.tgz", + "integrity": "sha512-lfiJIIC4Xayt5ItynE407ehlE03pCjeOc4hkR4yxxvvNJ4kuiN25B0g+Qp8XagYz361LLL7DCzR5bvFJ81QKtQ==", "license": "MIT", "dependencies": { "lib0": "^0.2.99" diff --git a/vibecoder/package.json b/vibecoder/package.json index 71327e893..9e52cc3a7 100644 --- a/vibecoder/package.json +++ b/vibecoder/package.json @@ -27,7 +27,7 @@ "@xyflow/react": "^12.11.2", "dompurify": "^3.4.13", "fuse.js": "^7.5.0", - "lucide-react": "^1.28.0", + "lucide-react": "^1.29.0", "react": "^19.2.8", "react-dom": "^19.2.8", "react-markdown": "^10.1.0", @@ -35,8 +35,8 @@ "xterm": "^5.3.0", "xterm-addon-fit": "^0.8.0", "y-monaco": "^0.1.6", - "y-websocket": "^3.0.0", - "yjs": "^13.6.31" + "y-websocket": "^3.1.0", + "yjs": "^13.6.32" }, "devDependencies": { "@eslint/js": "^10.0.1", @@ -53,12 +53,12 @@ "eslint": "^10.8.0", "eslint-plugin-no-unsanitized": "^4.1.2", "eslint-plugin-react-hooks": "^7.0.1", - "jsdom": "^29.0.0", - "monaco-editor": "^0.55.1", + "jsdom": "^30.0.1", + "monaco-editor": "^0.56.0", "patch-package": "^8.0.1", "typescript": "~6.0.3", "typescript-eslint": "^8.66.0", - "vite": "^8.2.0", + "vite": "^8.2.1", "vitest": "^4.1.10" }, "overrides": { diff --git a/vibecoder/src-tauri/Cargo.toml b/vibecoder/src-tauri/Cargo.toml index a511c20a1..ee0023130 100644 --- a/vibecoder/src-tauri/Cargo.toml +++ b/vibecoder/src-tauri/Cargo.toml @@ -53,13 +53,13 @@ vibe-memory = { path = "../../vibe-memory" } vibecli_cli = { package = "vibecli", path = "../../vibecli/vibecli-cli" } # Voice input — the same daemon bridge VibeDesk and VibeAIChat use. vibe-desktop-voice = { path = "../../crates/vibe-desktop-voice" } -base64 = "0.22.1" +base64 = "0.23.1" chrono = "0.4.44" rusqlite = { version = "0.40", features = ["bundled"] } -chacha20poly1305 = "0.10" +chacha20poly1305 = "0.11" hostname = "0.4" sha2 = "0.10" -sysinfo = "0.36" +sysinfo = "0.39" tracing = "0.1" [dev-dependencies] diff --git a/vibecoder/src-tauri/src/commands.rs b/vibecoder/src-tauri/src/commands.rs index 4c4527d63..bed6b544a 100644 --- a/vibecoder/src-tauri/src/commands.rs +++ b/vibecoder/src-tauri/src/commands.rs @@ -8508,6 +8508,7 @@ pub async fn diffcomplete_generate( after_context: String, instruction: String, provider: String, + model: Option<String>, additional_files: Option<Vec<vibe_ai::diffcomplete::AdditionalFile>>, previous_diff: Option<String>, refinement: Option<String>, @@ -8535,16 +8536,7 @@ pub async fn diffcomplete_generate( project_memory, }; - let active = { - let mut chat_engine = state.chat_engine.lock().await; - if !provider.is_empty() { - let _ = chat_engine.set_provider_by_name(&provider); - } - chat_engine - .active_provider() - .cloned() - .ok_or_else(|| "No active AI provider configured".to_string())? - }; + let active = resolve_editing_provider(&state, &provider, model.as_deref()).await?; let response = vibe_ai::diffcomplete::generate(active, request) .await @@ -8557,6 +8549,89 @@ pub async fn diffcomplete_generate( }) } +/// Resolve the provider for an explicit-trigger editing surface (⌘. and ghost +/// text) from the toolbar's `provider` + `model` selection. +/// +/// Built per request via [`build_temp_provider`] rather than by calling +/// `set_provider_by_name` on the shared chat engine. The old path had two +/// faults: it dropped `model` entirely, so the toolbar's model selection never +/// reached the request, and `set_provider_by_name` mutates engine state — one +/// ⌘. with a different provider silently re-pointed the whole chat session. +/// +/// Falls back to the engine's active provider only when the caller sends no +/// selection at all, which is the "no model selected" case the hosts already +/// guard against. +async fn resolve_editing_provider( + state: &tauri::State<'_, AppState>, + provider: &str, + model: Option<&str>, +) -> Result<Arc<dyn vibe_ai::provider::AIProvider>, String> { + if !provider.is_empty() { + if let Some(model) = model.map(str::trim).filter(|m| !m.is_empty()) { + return build_temp_provider(provider, model).ok_or_else(|| { + format!("No API key configured for provider '{provider}'") + }); + } + } + + let chat_engine = state.chat_engine.lock().await; + chat_engine + .active_provider() + .cloned() + .ok_or_else(|| "No active AI provider configured".to_string()) +} + +// ── Ghost text — explicit-trigger inline completion ────────────────────────── + +/// Response for [`ghost_complete`]. +#[derive(serde::Serialize)] +pub struct GhostResponseDto { + pub completion: String, + pub model_name: String, + pub truncated: bool, +} + +/// Generate an inline completion for the cursor position. +/// +/// **This command must only be invoked from an explicit user gesture.** It has +/// no way to tell an explicit request from an automatic one; the gate lives in +/// the host's inline-completion provider, which returns early for the editor's +/// automatic trigger kind. See `vibe_ai::ghost` for why that boundary matters. +#[tauri::command] +pub async fn ghost_complete( + state: tauri::State<'_, AppState>, + file_path: String, + language: String, + prefix: String, + suffix: String, + provider: String, + model: Option<String>, +) -> Result<GhostResponseDto, String> { + let project_memory = read_active_workspace_path() + .as_deref() + .and_then(build_diffcomplete_project_memory); + + let request = vibe_ai::ghost::GhostRequest { + file_path, + language, + prefix, + suffix, + project_memory, + }; + + let active = resolve_editing_provider(&state, &provider, model.as_deref()).await?; + + let response = vibe_ai::ghost::generate(active, request) + .await + .map_err(|e| e.to_string())?; + + Ok(GhostResponseDto { + completion: response.completion, + model_name: response.model_name, + truncated: response.truncated, + }) +} + // ─── Build System Commands ─────────────────────────────────────────────────── #[derive(Debug, Clone, Serialize, Deserialize)] diff --git a/vibecoder/src-tauri/src/lib.rs b/vibecoder/src-tauri/src/lib.rs index d347ae891..cc6594971 100644 --- a/vibecoder/src-tauri/src/lib.rs +++ b/vibecoder/src-tauri/src/lib.rs @@ -510,6 +510,7 @@ pub fn run() { commands::get_sandbox_status, commands::set_sandbox_enabled, commands::diffcomplete_generate, + commands::ghost_complete, // Build System commands commands::list_workspace_subdirs, commands::detect_build_system, diff --git a/vibecoder/src/App.tsx b/vibecoder/src/App.tsx index 1547cfbf0..42f226dc8 100644 --- a/vibecoder/src/App.tsx +++ b/vibecoder/src/App.tsx @@ -3,7 +3,8 @@ import { useToast } from "./hooks/useToast"; import { useNotifications } from "./hooks/useNotifications"; import { useApiKeyMonitor } from "./hooks/useApiKeyMonitor"; import { useDaemonMonitor } from "./hooks/useDaemonMonitor"; -import { probeAndCacheDefaultProvider } from "./hooks/useModelRegistry"; +import { probeAndCacheDefaultProvider, PROVIDER_DEFAULT_MODEL } from "./hooks/useModelRegistry"; +import { registerGhostText, type GhostTextHandle } from "./lib/ghostText"; import { Toaster } from "./components/Toaster"; import { NotificationCenter } from "./components/NotificationCenter"; import Editor, { DiffEditor, OnMount } from "@monaco-editor/react"; @@ -191,6 +192,14 @@ function App() { selectedProviderRef.current = selectedProvider; }, [selectedProvider]); + // The toolbar selects a provider; the model is that provider's registry + // default, the same resolution every other panel uses. Sent explicitly with + // each AI-editing request so the backend never has to guess one — and never + // re-points the shared chat engine to find out. + const selectedModel = PROVIDER_DEFAULT_MODEL[selectedProvider] ?? ""; + const selectedModelRef = useRef<string>(selectedModel); + selectedModelRef.current = selectedModel; + // Listen for file-tree refresh requests from child panels (e.g. Screenshot to App) useEffect(() => { const handler = () => { if (currentDirectory) loadDirectory(currentDirectory); }; @@ -658,6 +667,7 @@ function App() { activeFilePathRef.current = activeFilePath; const lspBridgeRef = useRef<LspBridge | null>(null); const lspNoticesRef = useRef(new Set<string>()); + const ghostTextRef = useRef<GhostTextHandle | null>(null); /** Tell the user once per language why IntelliSense is quiet. */ const reportLspUnavailable = useCallback((support: LspLanguageSupport) => { @@ -685,6 +695,10 @@ function App() { useEffect(() => () => { lspBridgeRef.current?.dispose(); lspBridgeRef.current = null; + // Registered on "*", so leaking it would leave a dead provider consulted + // on every keystroke for the rest of the process. + ghostTextRef.current?.dispose(); + ghostTextRef.current = null; }, []); // Now that each file gets its own Monaco model (see the editor's `path` @@ -736,6 +750,28 @@ function App() { } ); + // ── Ctrl+Space (⌥\ on mac too): ghost text ── + // The provider answers only Monaco's `Explicit` trigger kind, so this + // chord is the sole path to a suggestion — typing never produces one. + // See `lib/ghostText.ts` for why that gate is the whole design. + const ghost = registerGhostText(monaco, { + invoke: <T,>(command: string, args?: Record<string, unknown>) => + invoke<T>(command, args), + getProvider: () => selectedProviderRef.current, + getModel: () => selectedModelRef.current, + getFilePath: () => activeFilePathRef.current ?? "", + onError: (message) => toast.warn(message), + // The cap lives in `vibe_ai::ghost`; don't restate the number here, it + // would go stale silently. The backend reports *that* it clipped. + onTruncated: () => + toast.info("Suggestion was clipped — accept it and re-trigger for more."), + }); + ghostTextRef.current = ghost; + editor.addCommand( + monaco.KeyMod.Alt | monaco.KeyCode.Backslash, + () => ghost.trigger(editor), + ); + // IntelliSense: completion, hover, go-to-definition, signature help and // diagnostics, all driven from `lib/lsp.ts`. Providers are registered // lazily, per language, the first time a file of that language is opened — @@ -1017,6 +1053,19 @@ function App() { action: handleNewFolder, }, // Editor actions + { + id: 'editor.ghostText', + label: 'AI: Inline Completion at Cursor', + category: 'Editor', + icon: <Icon name="sparkles" size={16} />, + shortcut: isMac ? '⌥\\' : 'Alt+\\', + action: () => { + const editor = editorRef.current; + if (!editor) return; + editor.focus(); + ghostTextRef.current?.trigger(editor); + }, + }, { id: 'editor.toggleSidebar', label: 'Toggle Sidebar', @@ -2135,6 +2184,11 @@ function App() { suggestOnTriggerCharacters: true, parameterHints: { enabled: true }, tabCompletion: "on", + // Renders ghost text and binds Tab to accept it. The + // widget being enabled does NOT mean suggestions are + // requested while typing — the provider answers only + // the explicit trigger kind (see lib/ghostText.ts). + inlineSuggest: { enabled: true }, }} /> ) @@ -2159,6 +2213,7 @@ function App() { const shift = isMac ? '⇧' : 'Shift+'; return [ [`${mod}.`, 'AI Edit (DiffComplete)'], + [isMac ? '⌥\\' : 'Alt+\\', 'AI Inline Completion'], [`${mod}K`, 'Command Palette'], [`${mod}${shift}P`, 'Command Palette'], [`${mod}J`, 'Toggle AI Panel'], @@ -2478,6 +2533,7 @@ function App() { selectionStartLine={diffComplete.selectionStartLine} selectionEndLine={diffComplete.selectionEndLine} provider={selectedProvider} + model={selectedModel} onApply={(modified) => { if (modified === null) return; const editor = editorRef.current; diff --git a/vibecoder/src/components/DiffCompleteModal.tsx b/vibecoder/src/components/DiffCompleteModal.tsx index 3a0679819..ccf531333 100644 --- a/vibecoder/src/components/DiffCompleteModal.tsx +++ b/vibecoder/src/components/DiffCompleteModal.tsx @@ -130,6 +130,13 @@ export interface DiffCompleteModalProps { selectionEndLine: number; /** Active provider id (e.g. "claude", "openai"). */ provider: string; + /** + * Model id for `provider`. Sent with the request so the backend uses the + * host's selection instead of re-pointing the shared chat engine to find a + * provider — which used to switch the model for the whole chat session as a + * side effect of a ⌘. press. + */ + model: string; /** Called with the modified file content on apply; null means cancelled. */ onApply: (modified: string | null) => void; } @@ -145,7 +152,7 @@ type ProviderStatus = "unknown" | "ready" | "no_providers"; export function DiffCompleteModal(props: DiffCompleteModalProps) { const { open, onClose, filePath, language, originalContent, selectionText, - selectionStartLine, selectionEndLine, provider, onApply } = props; + selectionStartLine, selectionEndLine, provider, model, onApply } = props; const [phase, setPhase] = useState<Phase>("prompt"); const [instruction, setInstruction] = useState(""); @@ -305,6 +312,7 @@ export function DiffCompleteModal(props: DiffCompleteModalProps) { afterContext, instruction: instruction.trim(), provider, + model, additionalFiles: additionalFiles.length ? additionalFiles : null, previousDiff: opts.previousDiff && opts.previousDiff.length ? opts.previousDiff : null, refinement: opts.refinement && opts.refinement.trim().length ? opts.refinement.trim() : null, diff --git a/vibecoder/src/components/__tests__/DiffCompleteModal.test.tsx b/vibecoder/src/components/__tests__/DiffCompleteModal.test.tsx index bad51407a..7cc431582 100644 --- a/vibecoder/src/components/__tests__/DiffCompleteModal.test.tsx +++ b/vibecoder/src/components/__tests__/DiffCompleteModal.test.tsx @@ -296,6 +296,7 @@ describe('DiffCompleteModal — flow', () => { selectionStartLine: 0, selectionEndLine: 0, provider: "mock", + model: "mock-model", onApply: vi.fn(), }; @@ -337,6 +338,11 @@ describe('DiffCompleteModal — flow', () => { language: "rust", instruction: "rename line 2", provider: "mock", + // The model must ride along with the provider. Without it the backend + // fell back to re-pointing the shared chat engine, which dropped the + // host's model choice and switched the whole chat session's provider + // as a side effect of a single ⌘. press. + model: "mock-model", })); }); @@ -717,6 +723,7 @@ describe('DiffCompleteModal — D1.2 autosave hooks', () => { selectionStartLine: 2, selectionEndLine: 2, provider: "mock", + model: "mock-model", onApply: vi.fn(), }; diff --git a/vibecoder/src/lib/__tests__/ghostText.test.ts b/vibecoder/src/lib/__tests__/ghostText.test.ts new file mode 100644 index 000000000..5b92fe86d --- /dev/null +++ b/vibecoder/src/lib/__tests__/ghostText.test.ts @@ -0,0 +1,283 @@ +import { describe, it, expect, vi } from "vitest"; +import { + fitCompletionToLine, + windowContext, + registerGhostText, + PREFIX_LINES, + SUFFIX_LINES, + type GhostTextDeps, +} from "../ghostText"; + +// ── Monaco stand-ins ────────────────────────────────────────────────────── +// Only the surface `registerGhostText` actually touches. Mirrors the real +// enum's numbering: Automatic = 0, Explicit = 1. The VS Code enum is the +// other way round, which is exactly why the gate must compare against a +// named member — see ghostText.ts's header. +const TRIGGER = { Automatic: 0, Explicit: 1 } as const; + +function fakeModel(lines: string[], languageId = "typescript") { + const lineAt = (n: number) => lines[n - 1] ?? ""; + return { + getLineCount: () => lines.length, + getLanguageId: () => languageId, + getLineMaxColumn: (n: number) => lineAt(n).length + 1, + getValueInRange: (range: { + startLineNumber: number; + startColumn: number; + endLineNumber: number; + endColumn: number; + }) => { + const slice: string[] = []; + for (let n = range.startLineNumber; n <= range.endLineNumber; n++) { + const text = lineAt(n); + const from = n === range.startLineNumber ? range.startColumn - 1 : 0; + const to = n === range.endLineNumber ? range.endColumn - 1 : text.length; + slice.push(text.slice(from, to)); + } + return slice.join("\n"); + }, + }; +} + +function fakeMonaco() { + const dispose = vi.fn(); + let registered: { + provideInlineCompletions: ( + model: unknown, + position: unknown, + context: { triggerKind: number }, + token: { isCancellationRequested: boolean }, + ) => Promise<{ items: unknown[] }>; + } | null = null; + return { + dispose, + get provider() { + if (!registered) throw new Error("provider was never registered"); + return registered; + }, + monaco: { + languages: { + InlineCompletionTriggerKind: TRIGGER, + registerInlineCompletionsProvider: (_selector: string, provider: never) => { + registered = provider; + return { dispose }; + }, + }, + } as never, + }; +} + +function deps(overrides: Partial<GhostTextDeps> = {}): GhostTextDeps { + return { + invoke: vi.fn().mockResolvedValue({ + completion: "return a + b;", + model_name: "test-model", + truncated: false, + }), + getProvider: () => "anthropic", + getModel: () => "claude-opus-5", + getFilePath: () => "/w/src/lib.ts", + onError: vi.fn(), + ...overrides, + }; +} + +const POSITION = { lineNumber: 2, column: 5 }; +const LIVE_TOKEN = { isCancellationRequested: false }; + +describe("windowContext", () => { + it("splits the buffer exactly at the cursor", () => { + const model = fakeModel(["function f() {", " ", "}"]); + const { prefix, suffix } = windowContext(model, POSITION); + expect(prefix).toBe("function f() {\n "); + expect(suffix).toBe("\n}"); + }); + + it("reports only the text between the cursor and end of line as restOfLine", () => { + const model = fakeModel(["const x = 1;", " foo(bar)", "}"]); + // Columns are 1-based: column 9 of " foo(bar)" sits just after the `(`. + const { restOfLine } = windowContext(model, { lineNumber: 2, column: 9 }); + expect(restOfLine).toBe("bar)"); + }); + + it("bounds the window rather than sending the whole file", () => { + const long = Array.from({ length: 1000 }, (_, i) => `line ${i}`); + const model = fakeModel(long); + const { prefix, suffix } = windowContext(model, { lineNumber: 500, column: 1 }); + expect(prefix.split("\n").length).toBe(PREFIX_LINES + 1); + expect(suffix.split("\n").length).toBe(SUFFIX_LINES + 1); + }); + + it("clamps at the start and end of the buffer", () => { + const model = fakeModel(["a", "b"]); + const { prefix, suffix } = windowContext(model, { lineNumber: 1, column: 1 }); + expect(prefix).toBe(""); + expect(suffix).toBe("a\nb"); + }); +}); + +describe("fitCompletionToLine", () => { + it("keeps a multi-line completion when only whitespace follows the cursor", () => { + const fitted = fitCompletionToLine("if (x) {\n y();\n}", " "); + expect(fitted).toEqual({ text: "if (x) {\n y();\n}", extendToEndOfLine: true }); + }); + + it("does not extend the range when the cursor is already at end of line", () => { + const fitted = fitCompletionToLine("a + b", ""); + expect(fitted).toEqual({ text: "a + b", extendToEndOfLine: false }); + }); + + it("clips to one line when real code follows the cursor", () => { + // Monaco requires a multi-line insertText to end its range at a line end, + // and we cannot extend over `)` without eating it. + const fitted = fitCompletionToLine("a + b\nmore()", ")"); + expect(fitted).toEqual({ text: "a + b", extendToEndOfLine: false }); + }); + + it("returns null when nothing renderable remains", () => { + expect(fitCompletionToLine("", "")).toBeNull(); + expect(fitCompletionToLine("\nfoo()", ")")).toBeNull(); + }); +}); + +describe("registerGhostText — the explicit-trigger gate", () => { + it("returns nothing and calls no backend for an automatic trigger", async () => { + const fake = fakeMonaco(); + const d = deps(); + registerGhostText(fake.monaco, d); + + const result = await fake.provider.provideInlineCompletions( + fakeModel(["a", "bcde", "f"]), + POSITION, + { triggerKind: TRIGGER.Automatic }, + LIVE_TOKEN, + ); + + expect(result.items).toEqual([]); + expect(d.invoke).not.toHaveBeenCalled(); + }); + + it("answers an explicit trigger with a suggestion at the cursor", async () => { + const fake = fakeMonaco(); + const d = deps(); + registerGhostText(fake.monaco, d); + + const result = await fake.provider.provideInlineCompletions( + fakeModel(["function f() {", " ", "}"]), + POSITION, + { triggerKind: TRIGGER.Explicit }, + LIVE_TOKEN, + ); + + expect(d.invoke).toHaveBeenCalledWith("ghost_complete", { + filePath: "/w/src/lib.ts", + language: "typescript", + prefix: "function f() {\n ", + suffix: "\n}", + provider: "anthropic", + model: "claude-opus-5", + }); + expect(result.items).toHaveLength(1); + expect(result.items[0]).toMatchObject({ insertText: "return a + b;" }); + }); + + it("refuses to guess a provider when the toolbar has no selection", async () => { + const fake = fakeMonaco(); + const d = deps({ getProvider: () => "", getModel: () => "" }); + registerGhostText(fake.monaco, d); + + const result = await fake.provider.provideInlineCompletions( + fakeModel(["a", "bcde"]), + POSITION, + { triggerKind: TRIGGER.Explicit }, + LIVE_TOKEN, + ); + + expect(result.items).toEqual([]); + expect(d.invoke).not.toHaveBeenCalled(); + expect(d.onError).toHaveBeenCalledWith( + expect.stringContaining("Select a provider"), + ); + }); + + it("treats an empty completion as the model declining, not an error", async () => { + const fake = fakeMonaco(); + const d = deps({ + invoke: vi.fn().mockResolvedValue({ + completion: "", + model_name: "test-model", + truncated: false, + }), + }); + registerGhostText(fake.monaco, d); + + const result = await fake.provider.provideInlineCompletions( + fakeModel(["a", "bcde"]), + POSITION, + { triggerKind: TRIGGER.Explicit }, + LIVE_TOKEN, + ); + + expect(result.items).toEqual([]); + expect(d.onError).not.toHaveBeenCalled(); + }); + + it("surfaces a backend failure to the user", async () => { + const fake = fakeMonaco(); + const d = deps({ invoke: vi.fn().mockRejectedValue(new Error("no API key")) }); + registerGhostText(fake.monaco, d); + + const result = await fake.provider.provideInlineCompletions( + fakeModel(["a", "bcde"]), + POSITION, + { triggerKind: TRIGGER.Explicit }, + LIVE_TOKEN, + ); + + expect(result.items).toEqual([]); + expect(d.onError).toHaveBeenCalledWith(expect.stringContaining("no API key")); + }); + + it("drops a result whose request was cancelled mid-flight", async () => { + const fake = fakeMonaco(); + registerGhostText(fake.monaco, deps()); + + const result = await fake.provider.provideInlineCompletions( + fakeModel(["a", "bcde"]), + POSITION, + { triggerKind: TRIGGER.Explicit }, + { isCancellationRequested: true }, + ); + + expect(result.items).toEqual([]); + }); + + it("reports truncation without claiming a specific line count", async () => { + const fake = fakeMonaco(); + const onTruncated = vi.fn(); + const d = deps({ + onTruncated, + invoke: vi.fn().mockResolvedValue({ + completion: "a();", + model_name: "test-model", + truncated: true, + }), + }); + registerGhostText(fake.monaco, d); + + await fake.provider.provideInlineCompletions( + fakeModel(["a", "bcde"]), + POSITION, + { triggerKind: TRIGGER.Explicit }, + LIVE_TOKEN, + ); + + expect(onTruncated).toHaveBeenCalledOnce(); + }); + + it("disposes its registration", () => { + const fake = fakeMonaco(); + registerGhostText(fake.monaco, deps()).dispose(); + expect(fake.dispose).toHaveBeenCalledOnce(); + }); +}); diff --git a/vibecoder/src/lib/__tests__/lsp.test.ts b/vibecoder/src/lib/__tests__/lsp.test.ts index 63ef4086c..93be4ce72 100644 --- a/vibecoder/src/lib/__tests__/lsp.test.ts +++ b/vibecoder/src/lib/__tests__/lsp.test.ts @@ -23,6 +23,7 @@ import { parentDirectory, parseInstallHint, toLspPosition, + toLspCompletionContext, toMonacoCompletionItem, toMonacoCompletionKind, toMonacoCompletionList, @@ -1544,3 +1545,61 @@ describe("createLspBridge", () => { warn.mockRestore(); }); }); + +// ── Path B: LSP completion trigger context ──────────────────────────────── +// Monaco numbers these from 0, LSP from 1. The request used to be hardcoded +// to `{ triggerKind: 1 }`, so every completion claimed to be a manual invoke. +describe("toLspCompletionContext", () => { + // Monaco's real numbering. + const KINDS = { + Invoke: 0, + TriggerCharacter: 1, + TriggerForIncompleteCompletions: 2, + }; + + it("maps a manual invoke to LSP Invoked (1)", () => { + expect(toLspCompletionContext({ triggerKind: KINDS.Invoke }, KINDS)).toEqual({ + triggerKind: 1, + }); + }); + + it("maps a trigger character to LSP TriggerCharacter (2) and forwards it", () => { + expect( + toLspCompletionContext( + { triggerKind: KINDS.TriggerCharacter, triggerCharacter: "." }, + KINDS, + ), + ).toEqual({ triggerKind: 2, triggerCharacter: "." }); + }); + + it("maps an incomplete-refilter to LSP TriggerForIncompleteCompletions (3)", () => { + expect( + toLspCompletionContext( + { triggerKind: KINDS.TriggerForIncompleteCompletions }, + KINDS, + ), + ).toEqual({ triggerKind: 3 }); + }); + + it("omits triggerCharacter entirely when Monaco did not supply one", () => { + const ctx = toLspCompletionContext( + { triggerKind: KINDS.TriggerCharacter }, + KINDS, + ); + expect(ctx).toEqual({ triggerKind: 2 }); + expect("triggerCharacter" in ctx).toBe(false); + }); + + it("falls back to Invoked when Monaco passes no context at all", () => { + expect(toLspCompletionContext(undefined, KINDS)).toEqual({ triggerKind: 1 }); + }); + + it("never emits LSP's out-of-range 0", () => { + // Monaco's Invoke is 0 and LSP has no 0 — a naive pass-through would send + // it and some servers reject the request outright. + for (const kind of Object.values(KINDS)) { + expect(toLspCompletionContext({ triggerKind: kind }, KINDS).triggerKind) + .toBeGreaterThan(0); + } + }); +}); diff --git a/vibecoder/src/lib/ghostText.ts b/vibecoder/src/lib/ghostText.ts new file mode 100644 index 000000000..4d8320806 --- /dev/null +++ b/vibecoder/src/lib/ghostText.ts @@ -0,0 +1,227 @@ +/** + * Ghost text — explicit-trigger inline completion for Monaco. + * + * # The gate + * + * The previous ghost-text surface was removed in `5a7eef7c` because it was + * keystroke-driven. This one is not, and the single line that guarantees it is + * the `triggerKind` check in `provideInlineCompletions`: Monaco calls the + * provider for *both* `Automatic` (typing) and `Explicit` (the user asked), and + * we answer only the second. + * + * `InlineCompletionTriggerKind` is `{ Automatic: 0, Explicit: 1 }` in Monaco and + * `{ Invoke: 0, Automatic: 1 }` in VS Code — the *same names mean opposite + * numbers*. Compare against the named enum member, never a literal, and never + * copy this check between the two hosts. The VS Code side lives in + * `vscode-extension/src/ghost-text.ts` and has its own gate. + * + * There is deliberately no debounce timer and no edit-history buffer here. The + * request carries the window around the cursor and nothing else. + */ +import type * as Monaco from "monaco-editor"; + +/** Lines of context sent before the cursor. */ +export const PREFIX_LINES = 160; +/** Lines of context sent after the cursor. */ +export const SUFFIX_LINES = 60; + +export interface GhostResponse { + completion: string; + model_name: string; + truncated: boolean; +} + +export interface GhostTextDeps { + invoke: <T>(command: string, args?: Record<string, unknown>) => Promise<T>; + /** Toolbar provider selection. Empty string means "nothing selected". */ + getProvider: () => string; + /** Toolbar model selection. */ + getModel: () => string; + /** Absolute path of the active file, for the prompt header. */ + getFilePath: () => string; + /** Surfaced to the user; called for a failed request, not for an empty one. */ + onError: (message: string) => void; + /** Called when the model's answer was clipped by the backend line cap. */ + onTruncated?: () => void; +} + +/** The prefix/suffix window around a cursor position. */ +export interface ContextWindow { + prefix: string; + suffix: string; + /** Text between the cursor and the end of its line. */ + restOfLine: string; +} + +/** + * Slice the bounded window around the cursor. + * + * Exported for tests: the window is the entire hidden state this surface has, + * so what goes in it is worth pinning. + */ +export function windowContext( + model: Pick<Monaco.editor.ITextModel, "getLineCount" | "getValueInRange" | "getLineMaxColumn">, + position: Pick<Monaco.Position, "lineNumber" | "column">, +): ContextWindow { + const lineCount = model.getLineCount(); + const firstLine = Math.max(1, position.lineNumber - PREFIX_LINES); + const lastLine = Math.min(lineCount, position.lineNumber + SUFFIX_LINES); + const endColumn = model.getLineMaxColumn(lastLine); + const lineEndColumn = model.getLineMaxColumn(position.lineNumber); + + return { + prefix: model.getValueInRange({ + startLineNumber: firstLine, + startColumn: 1, + endLineNumber: position.lineNumber, + endColumn: position.column, + }), + suffix: model.getValueInRange({ + startLineNumber: position.lineNumber, + startColumn: position.column, + endLineNumber: lastLine, + endColumn, + }), + restOfLine: model.getValueInRange({ + startLineNumber: position.lineNumber, + startColumn: position.column, + endLineNumber: position.lineNumber, + endColumn: lineEndColumn, + }), + }; +} + +/** How a completion must be shaped to render correctly at the cursor. */ +export interface FittedCompletion { + text: string; + /** + * When true the replacement range runs to the end of the line, which is what + * Monaco requires of a multi-line `insertText`. Only safe when the text being + * swallowed is whitespace. + */ + extendToEndOfLine: boolean; +} + +/** + * Constrain a completion so Monaco can render it at the cursor. + * + * Monaco requires that a multi-line `insertText` end its range at the end of a + * line. When real code follows the cursor on the same line we cannot extend the + * range without eating it, so the suggestion is clipped to its first line. + * Returns `null` when nothing renderable remains. + */ +export function fitCompletionToLine( + completion: string, + restOfLine: string, +): FittedCompletion | null { + if (completion.length === 0) return null; + + // Trailing whitespace after the cursor can be swallowed; real text cannot. + if (restOfLine.trim().length === 0) { + return { text: completion, extendToEndOfLine: restOfLine.length > 0 }; + } + + const firstLine = completion.split("\n")[0]; + if (firstLine.trim().length === 0) return null; + return { text: firstLine, extendToEndOfLine: false }; +} + +export interface GhostTextHandle { + dispose: () => void; + /** + * Ask Monaco for an explicit inline suggestion. This is the only path that + * reaches the provider with `Explicit`, so it is the only path that produces + * a suggestion. + */ + trigger: (editor: Monaco.editor.ICodeEditor) => void; +} + +/** + * Register the explicit-trigger inline completion provider for all languages. + * + * Registering on `"*"` is safe precisely because of the trigger gate: the + * provider is consulted constantly but answers only when asked. + */ +export function registerGhostText( + monaco: typeof Monaco, + deps: GhostTextDeps, +): GhostTextHandle { + const registration = monaco.languages.registerInlineCompletionsProvider("*", { + provideInlineCompletions: async (model, position, context, token) => { + // ── The gate. See the module header before touching this. ── + if ( + context.triggerKind !== + monaco.languages.InlineCompletionTriggerKind.Explicit + ) { + return { items: [] }; + } + + const provider = deps.getProvider(); + const selectedModel = deps.getModel(); + if (!provider || !selectedModel) { + // Matches the provider-agnostic rule: no toolbar selection means no + // request, never a silent default to one vendor. + deps.onError("Select a provider and model in the toolbar first."); + return { items: [] }; + } + + const { prefix, suffix, restOfLine } = windowContext(model, position); + + let response: GhostResponse; + try { + response = await deps.invoke<GhostResponse>("ghost_complete", { + filePath: deps.getFilePath(), + language: model.getLanguageId(), + prefix, + suffix, + provider, + model: selectedModel, + }); + } catch (error) { + deps.onError( + `Inline completion failed: ${ + error instanceof Error ? error.message : String(error) + }`, + ); + return { items: [] }; + } + + // The user moved on while the request was in flight. + if (token.isCancellationRequested) return { items: [] }; + + // An empty completion is the model declining, not a failure — say + // nothing rather than reporting an error the user cannot act on. + const fitted = fitCompletionToLine(response.completion, restOfLine); + if (!fitted) return { items: [] }; + + if (response.truncated) deps.onTruncated?.(); + + const endColumn = fitted.extendToEndOfLine + ? model.getLineMaxColumn(position.lineNumber) + : position.column; + + return { + items: [ + { + insertText: fitted.text, + range: { + startLineNumber: position.lineNumber, + startColumn: position.column, + endLineNumber: position.lineNumber, + endColumn, + }, + }, + ], + }; + }, + // Nothing is retained per request, so there is nothing to release. + disposeInlineCompletions: () => {}, + }); + + return { + dispose: () => registration.dispose(), + trigger: (editor) => { + editor.trigger("ghost-text", "editor.action.inlineSuggest.trigger", {}); + }, + }; +} diff --git a/vibecoder/src/lib/lsp.ts b/vibecoder/src/lib/lsp.ts index 0adfe379c..0e8dc5acc 100644 --- a/vibecoder/src/lib/lsp.ts +++ b/vibecoder/src/lib/lsp.ts @@ -65,6 +65,11 @@ export interface MonacoLspEnums { readonly completionKinds: MonacoCompletionKinds; readonly insertAsSnippet: number; readonly deprecatedTag: number; + readonly completionTriggerKinds: { + readonly Invoke: number; + readonly TriggerCharacter: number; + readonly TriggerForIncompleteCompletions: number; + }; readonly markerSeverity: { readonly Error: number; readonly Warning: number; @@ -80,10 +85,56 @@ export function enumsFromMonaco(monaco: typeof Monaco): MonacoLspEnums { insertAsSnippet: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet, deprecatedTag: monaco.languages.CompletionItemTag.Deprecated, + completionTriggerKinds: monaco.languages.CompletionTriggerKind, markerSeverity: monaco.MarkerSeverity, }; } +/** + * The `context` field of an LSP `textDocument/completion` request. + * + * LSP numbers these from 1 (`Invoked = 1`, `TriggerCharacter = 2`, + * `TriggerForIncompleteCompletions = 3`); Monaco numbers the same three from 0. + * They are *not* interchangeable, which is why the mapping below is explicit + * rather than `monacoKind + 1`. + */ +export interface LspCompletionContext { + triggerKind: 1 | 2 | 3; + triggerCharacter?: string; +} + +/** + * Translate Monaco's completion context into LSP's. + * + * This used to be hardcoded to `{ triggerKind: 1 }` — every request claimed to + * be a manual invoke. Servers use this to decide what to offer: a member list + * after `.` is gated on `TriggerCharacter` by several servers, and a server + * that returned `isIncomplete` expects `TriggerForIncompleteCompletions` on the + * refilter rather than a fresh invoke. + */ +export function toLspCompletionContext( + context: { triggerKind: number; triggerCharacter?: string } | undefined, + kinds: MonacoLspEnums["completionTriggerKinds"], +): LspCompletionContext { + if (!context) return { triggerKind: 1 }; + + if (context.triggerKind === kinds.TriggerCharacter) { + return { + triggerKind: 2, + // A TriggerCharacter request without the character is malformed; omit + // the field rather than send `triggerCharacter: undefined`, which some + // servers reject outright. + ...(context.triggerCharacter !== undefined + ? { triggerCharacter: context.triggerCharacter } + : {}), + }; + } + if (context.triggerKind === kinds.TriggerForIncompleteCompletions) { + return { triggerKind: 3 }; + } + return { triggerKind: 1 }; +} + // ── LSP wire types ────────────────────────────────────────────────────────── export interface LspPosition { @@ -1088,7 +1139,7 @@ export function createLspBridge( const disposables: Monaco.IDisposable[] = [ monaco.languages.registerCompletionItemProvider(monacoLanguage, { triggerCharacters: triggerList, - provideCompletionItems: async (model, position) => { + provideCompletionItems: async (model, position, completionContext) => { const document = documentFor(model); if (!document) return { suggestions: [] }; // The edit that triggered this completion may still be queued; the @@ -1111,7 +1162,10 @@ export function createLspBridge( params: { textDocument: { uri: document.uri }, position: toLspPosition(position), - context: { triggerKind: 1 }, + context: toLspCompletionContext( + completionContext, + enums.completionTriggerKinds, + ), }, }, ); diff --git a/vibedesk/package-lock.json b/vibedesk/package-lock.json index 350bfd46f..b737abe63 100644 --- a/vibedesk/package-lock.json +++ b/vibedesk/package-lock.json @@ -10,7 +10,7 @@ "dependencies": { "@tauri-apps/api": "^2.11.1", "@tauri-apps/plugin-dialog": "^2.7.2", - "lucide-react": "^1.28.0", + "lucide-react": "^1.29.0", "react": "^19.2.8", "react-dom": "^19.2.8", "react-markdown": "^10.1.0", @@ -310,9 +310,9 @@ } }, "node_modules/@tauri-apps/cli": { - "version": "2.11.2", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-2.11.2.tgz", - "integrity": "sha512-bk3HemqvGRoy+5D/dVMUQHKMYLglD0jVnMm/0iGMH6ufZ+p8r14m6BpIixwij3PBvZdvORUp1YifTD8QxVZ1Nw==", + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-2.11.4.tgz", + "integrity": "sha512-R8xGtMpwyetawSqm9kYOuMmEqkhUbvcUy8n0aNXIxollKBLESUu5f4Fx+64hgASYm1H+jSWq6jCW6zqTnH6hqQ==", "dev": true, "license": "Apache-2.0 OR MIT", "bin": { @@ -326,23 +326,23 @@ "url": "https://opencollective.com/tauri" }, "optionalDependencies": { - "@tauri-apps/cli-darwin-arm64": "2.11.2", - "@tauri-apps/cli-darwin-x64": "2.11.2", - "@tauri-apps/cli-linux-arm-gnueabihf": "2.11.2", - "@tauri-apps/cli-linux-arm64-gnu": "2.11.2", - "@tauri-apps/cli-linux-arm64-musl": "2.11.2", - "@tauri-apps/cli-linux-riscv64-gnu": "2.11.2", - "@tauri-apps/cli-linux-x64-gnu": "2.11.2", - "@tauri-apps/cli-linux-x64-musl": "2.11.2", - "@tauri-apps/cli-win32-arm64-msvc": "2.11.2", - "@tauri-apps/cli-win32-ia32-msvc": "2.11.2", - "@tauri-apps/cli-win32-x64-msvc": "2.11.2" + "@tauri-apps/cli-darwin-arm64": "2.11.4", + "@tauri-apps/cli-darwin-x64": "2.11.4", + "@tauri-apps/cli-linux-arm-gnueabihf": "2.11.4", + "@tauri-apps/cli-linux-arm64-gnu": "2.11.4", + "@tauri-apps/cli-linux-arm64-musl": "2.11.4", + "@tauri-apps/cli-linux-riscv64-gnu": "2.11.4", + "@tauri-apps/cli-linux-x64-gnu": "2.11.4", + "@tauri-apps/cli-linux-x64-musl": "2.11.4", + "@tauri-apps/cli-win32-arm64-msvc": "2.11.4", + "@tauri-apps/cli-win32-ia32-msvc": "2.11.4", + "@tauri-apps/cli-win32-x64-msvc": "2.11.4" } }, "node_modules/@tauri-apps/cli-darwin-arm64": { - "version": "2.11.2", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-2.11.2.tgz", - "integrity": "sha512-+4UZzLt+eOAEQCwgd+TqKgyUJMrvx+BgdXLLaqJYmPqzP+nE6YZr/hY6CWLYGQb8jFn99jEkmC6uA3tNvamA1w==", + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-2.11.4.tgz", + "integrity": "sha512-1ryOF3ZhpZ/nemHV5zVwBQBz9jDGKmKPvWPADOhc83ig0P4bMc2iER4NbC6r9sjeIZ6RVQ4g3RZIYvezhcl4TQ==", "cpu": [ "arm64" ], @@ -357,9 +357,9 @@ } }, "node_modules/@tauri-apps/cli-darwin-x64": { - "version": "2.11.2", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-2.11.2.tgz", - "integrity": "sha512-VjYYtZUPqDMLutSfJEyxFE3Bz+DPi7c8wC3imckgvciLDZLq4qwKJxBicg0BXGhXjJsl8vKWgWRFNMPELQ+Xyg==", + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-2.11.4.tgz", + "integrity": "sha512-uFsGQAAfuyz1k/yGLmkWfkBlgKAqZfxqlHmLWx81QU27RJWfmbNHCIq8T8w1e+VClleIuZUjpHWfoE4E3DLo3A==", "cpu": [ "x64" ], @@ -374,9 +374,9 @@ } }, "node_modules/@tauri-apps/cli-linux-arm-gnueabihf": { - "version": "2.11.2", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-2.11.2.tgz", - "integrity": "sha512-yMemD6f4i95AQriS8EazyOFzbE34yjnP16i3IOzpHGQvBoy2DjypFMFBq0NtPuITURv/cOGguRtHR5d79/9CSA==", + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-2.11.4.tgz", + "integrity": "sha512-IaHZn5CdBL21oUmjiVOS1ctw6Ip1O0pjp70FwOWmYz1myWe0SY96ZIj2FYf7pT0m8bI2h/hrs5ZbEXXh44/MkQ==", "cpu": [ "arm" ], @@ -391,9 +391,9 @@ } }, "node_modules/@tauri-apps/cli-linux-arm64-gnu": { - "version": "2.11.2", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-2.11.2.tgz", - "integrity": "sha512-cgI91D2wL8GSgoWwZXDqt+DwnuZCP2/bz03QAE4TrhgAKIsrB4hX26W/H1EONPUUNkqrsgeCD0wU6pcNjV/5kw==", + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-2.11.4.tgz", + "integrity": "sha512-N41/ukTRVe6XSuUTESuFdGeOW2i7k62tK+6gHK5Kd5/q5RPvvi19GaWAVPPb9u95HSGmTChSolBfzynUsssFaA==", "cpu": [ "arm64" ], @@ -411,9 +411,9 @@ } }, "node_modules/@tauri-apps/cli-linux-arm64-musl": { - "version": "2.11.2", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.11.2.tgz", - "integrity": "sha512-X1rm0BERqAAggtYTESSgXrS3sz4Sb/OiPiz54UqISlXW+GkR3vNIGnsy/lejNmoXGVqri3Q53BCfQiclOIyRPw==", + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.11.4.tgz", + "integrity": "sha512-v277UnT/fB64xAfSroL5N3Km3tLmvATWqJJw/wRI+g6o+HkeD0slyE7gOhNs1MbjE41R7bQOTxMVoL3aomUJmw==", "cpu": [ "arm64" ], @@ -431,9 +431,9 @@ } }, "node_modules/@tauri-apps/cli-linux-riscv64-gnu": { - "version": "2.11.2", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-riscv64-gnu/-/cli-linux-riscv64-gnu-2.11.2.tgz", - "integrity": "sha512-usbMLJbT3KtkOrBMDVeGYNM35aTHXx38SJSzTMSqqjeUIOQ+iVPjb2yAGNAE+KqmBbAx4FOFIyMeKXx2M/JKGQ==", + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-riscv64-gnu/-/cli-linux-riscv64-gnu-2.11.4.tgz", + "integrity": "sha512-qqgNkQ2u1yZHxjhxsZaxUtRDW8dIqIYm33rx/mzwQv0SfY9x1B+iraj8vWeFiXjjSVVhEMepXSOts1TqPzvXNQ==", "cpu": [ "riscv64" ], @@ -451,9 +451,9 @@ } }, "node_modules/@tauri-apps/cli-linux-x64-gnu": { - "version": "2.11.2", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-2.11.2.tgz", - "integrity": "sha512-Ru4gwJKPG0ctVGchRGpRup4Y4lW2SSfFnrbQcyHhCliKy4g8Qz97TrUgCur4CbWyAgKxvGh3SjrkA0LDYzDGiw==", + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-2.11.4.tgz", + "integrity": "sha512-2VRNWl84FOH0m2giiDkO2h0QXlcMJeX+zJDpI5kDIQAx6s+geF3v48F4DXfJez4GS/FdoDGnPnw1C2iYGbQ7bQ==", "cpu": [ "x64" ], @@ -471,9 +471,9 @@ } }, "node_modules/@tauri-apps/cli-linux-x64-musl": { - "version": "2.11.2", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-2.11.2.tgz", - "integrity": "sha512-eUm7T6clN1MMmNSRQ9gaWsQdyehQx2Gmn5hht/QUlqZQI/qcP2OJK5dnaxqwFzCr2HdsEo9ydxaqcS1oJzMvUw==", + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-2.11.4.tgz", + "integrity": "sha512-o9GyhYor/nc7xarmwDE3ka2szuW3uuZzXjHWh64Q8YX5AtSgxdQkFWzrY4O8KiGtVNvFBI14H3Q49Qj5TOIP/A==", "cpu": [ "x64" ], @@ -491,9 +491,9 @@ } }, "node_modules/@tauri-apps/cli-win32-arm64-msvc": { - "version": "2.11.2", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-2.11.2.tgz", - "integrity": "sha512-HeeZW80jU+gVTOEX4X/hC6NVSAdDVXajwP5fxIZ/3z9WvUC7qrudX2GMTilYq6Dg0e0sk0XgsAJD1hZ5wPBXUA==", + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-2.11.4.tgz", + "integrity": "sha512-ld5Ehb598m0VkYyylRPNeCFsBe/km0jxis6KgMpl3IGY6I/i1RwQXO05I1AsXUXO2WC6AvB/Lw4qTf/asiuEiQ==", "cpu": [ "arm64" ], @@ -508,9 +508,9 @@ } }, "node_modules/@tauri-apps/cli-win32-ia32-msvc": { - "version": "2.11.2", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-2.11.2.tgz", - "integrity": "sha512-YhjQNZcXfbkCLyazSv1nPnJ9iRFE1wm6kc51FDbU10/Dk09io+6PAGMLjkxnX2GdM0qMnDmTjstY8mTDVvtKeA==", + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-2.11.4.tgz", + "integrity": "sha512-12Hxi0XX/H5VFxO/bGgHkFWhml9VMgEOu9CidjeCeTNQ1l6fpUlbiGgSP7CLI3PFtW9/FfbeHieZ+kyWK5H7CA==", "cpu": [ "ia32" ], @@ -525,9 +525,9 @@ } }, "node_modules/@tauri-apps/cli-win32-x64-msvc": { - "version": "2.11.2", - "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-2.11.2.tgz", - "integrity": "sha512-d2JchlFIpZevZVReyqhQOekJmb1UH3rhZ5VX6sH3ty9ETE0TKQavpihvoScUXfKKpW6HZC0MrFGRU0ZtD+w3gA==", + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-2.11.4.tgz", + "integrity": "sha512-+vDiqBIU5dMISg/wNvX3sF+ZHfgJGJ5T0AcO+EHNXV9GGAG+P5fzodlDXD3QdKCRgZxMoCm5PPvj3BqLNjBthw==", "cpu": [ "x64" ], @@ -1600,9 +1600,9 @@ } }, "node_modules/lucide-react": { - "version": "1.28.0", - "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-1.28.0.tgz", - "integrity": "sha512-fARAFJULsGuDDydjp6+6blekG/sBIM29TerzLjc9bQUKAcEfrSc4ZQKb25KRz4OMKd87cZTb5dgq0w/T6KufVg==", + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-1.29.0.tgz", + "integrity": "sha512-Xs9QFG5+9sNX04MdKVT4++umA+hJ2qsJVlRlRWHQ7qZobXgMiNHSpZ5eZm8JUoGCdNyoEdXoEwa8HVr0DNjOQg==", "license": "ISC", "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" diff --git a/vibedesk/package.json b/vibedesk/package.json index 6da829c5c..b6b903bb2 100644 --- a/vibedesk/package.json +++ b/vibedesk/package.json @@ -18,7 +18,7 @@ "dependencies": { "@tauri-apps/api": "^2.11.1", "@tauri-apps/plugin-dialog": "^2.7.2", - "lucide-react": "^1.28.0", + "lucide-react": "^1.29.0", "react": "^19.2.8", "react-dom": "^19.2.8", "react-markdown": "^10.1.0", diff --git a/vibemobile/android/gradle/wrapper/gradle-wrapper.properties b/vibemobile/android/gradle/wrapper/gradle-wrapper.properties index f98345f0f..c4a03016d 100644 --- a/vibemobile/android/gradle/wrapper/gradle-wrapper.properties +++ b/vibemobile/android/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.6.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.7.0-all.zip diff --git a/vibemobile/android/settings.gradle.kts b/vibemobile/android/settings.gradle.kts index adb282659..69f4320c1 100644 --- a/vibemobile/android/settings.gradle.kts +++ b/vibemobile/android/settings.gradle.kts @@ -19,7 +19,7 @@ pluginManagement { plugins { id("dev.flutter.flutter-plugin-loader") version "1.0.0" id("com.android.application") version "9.3.1" apply false - id("org.jetbrains.kotlin.android") version "2.1.0" apply false + id("org.jetbrains.kotlin.android") version "2.4.10" apply false } include(":app") diff --git a/vibemobile/pubspec.lock b/vibemobile/pubspec.lock index 7b13349f7..9f3e16fe9 100644 --- a/vibemobile/pubspec.lock +++ b/vibemobile/pubspec.lock @@ -122,18 +122,18 @@ packages: dependency: "direct main" description: name: flutter_secure_storage - sha256: "7686b1d6a29985dcbb808c59518226e603e3bfa7c0ddfd1a0d00e4cda77c868e" + sha256: "15e8c8fe269fdf7d469b23008ab3df521c8b826ed345820532364c31bdebace6" url: "https://pub.dev" source: hosted - version: "10.3.1" + version: "11.0.0" flutter_secure_storage_darwin: dependency: transitive description: name: flutter_secure_storage_darwin - sha256: "82329fa5cdf343773b1b6897dea959105a29f092454259edff92f9f6637e8149" + sha256: ac6d76a752de0cd738334eb4b21743fc4943f449f5b6e308f18838b048c02ac0 url: "https://pub.dev" source: hosted - version: "0.3.2" + version: "0.4.0" flutter_secure_storage_linux: dependency: transitive description: diff --git a/vibemobile/pubspec.yaml b/vibemobile/pubspec.yaml index 5e9d31e4d..168790849 100644 --- a/vibemobile/pubspec.yaml +++ b/vibemobile/pubspec.yaml @@ -13,7 +13,7 @@ dependencies: http: ^1.4.0 provider: ^6.1.5 shared_preferences: ^2.5.3 - flutter_secure_storage: ^10.3.1 + flutter_secure_storage: ^11.0.0 mobile_scanner: ^7.4.0 multicast_dns: ^0.3.2+1 speech_to_text: ^7.4.0 diff --git a/vibewatch/VibeCodyWear/gradle/wrapper/gradle-wrapper.jar b/vibewatch/VibeCodyWear/gradle/wrapper/gradle-wrapper.jar index b1b8ef56b44f16b14dc800fa8103a6d89abb526f..eddabd2eef8d94a5437d6168ff9c87a78ff725b3 100644 GIT binary patch delta 39079 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 F{Rc_uT_ykk delta 40101 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 diff --git a/vibewatch/VibeCodyWear/gradle/wrapper/gradle-wrapper.properties b/vibewatch/VibeCodyWear/gradle/wrapper/gradle-wrapper.properties index a351597e6..1e922f407 100644 --- a/vibewatch/VibeCodyWear/gradle/wrapper/gradle-wrapper.properties +++ b/vibewatch/VibeCodyWear/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.6.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.7.0-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/vscode-extension/package-lock.json b/vscode-extension/package-lock.json index 1b2b18024..0dc02d1ec 100644 --- a/vscode-extension/package-lock.json +++ b/vscode-extension/package-lock.json @@ -252,92 +252,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.66.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.66.0.tgz", - "integrity": "sha512-p088eaGrzYz1s+7cov0aMOCkNGTJlVxF4jgubf28c8L0Cv9Rloj8YBHnv4hXLq6IIEE1AsjNWavO+k+8kP2Y0A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.66.0", - "@typescript-eslint/type-utils": "8.66.0", - "@typescript-eslint/utils": "8.66.0", - "@typescript-eslint/visitor-keys": "8.66.0", - "ignore": "^7.0.5", - "natural-compare": "^1.4.0", - "ts-api-utils": "^2.5.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^8.66.0", - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.6.tgz", - "integrity": "sha512-BAg6QkE8W+TuQLrrw0Ugr7HegXduRuuj8/ti2kSOc+jz1dmx8/WNcjr6XGnq5YpDWxFwwaavqD0+jIUOKelTsw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "8.66.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.66.0.tgz", - "integrity": "sha512-X6ypGChaWYk6PBtUg2BwuTZEFFcHJAtGTVJ9/lCTOufhZ4i9fNolQNnktq+kkMCwMj7V8Svsq7+TxSDslmhE0g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/scope-manager": "8.66.0", - "@typescript-eslint/types": "8.66.0", - "@typescript-eslint/typescript-estree": "8.66.0", - "@typescript-eslint/visitor-keys": "8.66.0", - "debug": "^4.4.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/project-service": { - "version": "8.66.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.66.0.tgz", - "integrity": "sha512-7MthGPTt4BP69lSryqpqq8HQqxuzynssckL/jyDyk3+TNMQ3y2jFWkptCrktWvBrP+EH787Nl5N5Qpw7WZg+5g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.66.0", - "@typescript-eslint/types": "^8.66.0", - "debug": "^4.4.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.1.0" - } - }, "node_modules/@typescript-eslint/scope-manager": { "version": "8.66.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.66.0.tgz", @@ -356,48 +270,6 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.66.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.66.0.tgz", - "integrity": "sha512-9D5gLYZG4rOjcoag8MQ/fWI8WqA9wcPDyOGyWtWFhvM1lHRbliqUSPIY5J3zqCU1tvSwzXxnnjhQhz5Ne7mJ4g==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "8.66.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.66.0.tgz", - "integrity": "sha512-LG2dWfjZQQp0ADtAu/EWJVayefGL2UEZ3CDeI44D9v3rXB/WYUqE/jpO28KrEKul5AySrmI+Zh1v6v+xW2U9+g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.66.0", - "@typescript-eslint/typescript-estree": "8.66.0", - "@typescript-eslint/utils": "8.66.0", - "debug": "^4.4.3", - "ts-api-utils": "^2.5.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.1.0" - } - }, "node_modules/@typescript-eslint/types": { "version": "8.66.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.66.0.tgz", @@ -412,58 +284,6 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.66.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.66.0.tgz", - "integrity": "sha512-8/x4INiiQb10jGgXYD7116/zQ+OL84ZIFn0za68wwFHCanT/VLbBEroWht8RV8fn0/ZCAoazHLQgwUC0UQcDfg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/project-service": "8.66.0", - "@typescript-eslint/tsconfig-utils": "8.66.0", - "@typescript-eslint/types": "8.66.0", - "@typescript-eslint/visitor-keys": "8.66.0", - "debug": "^4.4.3", - "minimatch": "^10.2.2", - "semver": "^7.7.3", - "tinyglobby": "^0.2.15", - "ts-api-utils": "^2.5.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "8.66.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.66.0.tgz", - "integrity": "sha512-jasearZPolBw5NJNYGMwxzHMF83niVWmMU1VdHzG1CyfI2VS7f7nZltnKtHcg20hW+7Uo5GfK4MeDPoU3qI8EA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.66.0", - "@typescript-eslint/types": "8.66.0", - "@typescript-eslint/typescript-estree": "8.66.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.1.0" - } - }, "node_modules/@typescript-eslint/visitor-keys": { "version": "8.66.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.66.0.tgz", @@ -1211,6 +1031,186 @@ "typescript": ">=4.8.4 <6.1.0" } }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.66.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.66.0.tgz", + "integrity": "sha512-p088eaGrzYz1s+7cov0aMOCkNGTJlVxF4jgubf28c8L0Cv9Rloj8YBHnv4hXLq6IIEE1AsjNWavO+k+8kP2Y0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.66.0", + "@typescript-eslint/type-utils": "8.66.0", + "@typescript-eslint/utils": "8.66.0", + "@typescript-eslint/visitor-keys": "8.66.0", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.66.0", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils": { + "version": "8.66.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.66.0.tgz", + "integrity": "sha512-LG2dWfjZQQp0ADtAu/EWJVayefGL2UEZ3CDeI44D9v3rXB/WYUqE/jpO28KrEKul5AySrmI+Zh1v6v+xW2U9+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.66.0", + "@typescript-eslint/typescript-estree": "8.66.0", + "@typescript-eslint/utils": "8.66.0", + "debug": "^4.4.3", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/parser": { + "version": "8.66.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.66.0.tgz", + "integrity": "sha512-X6ypGChaWYk6PBtUg2BwuTZEFFcHJAtGTVJ9/lCTOufhZ4i9fNolQNnktq+kkMCwMj7V8Svsq7+TxSDslmhE0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.66.0", + "@typescript-eslint/types": "8.66.0", + "@typescript-eslint/typescript-estree": "8.66.0", + "@typescript-eslint/visitor-keys": "8.66.0", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/typescript-estree": { + "version": "8.66.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.66.0.tgz", + "integrity": "sha512-8/x4INiiQb10jGgXYD7116/zQ+OL84ZIFn0za68wwFHCanT/VLbBEroWht8RV8fn0/ZCAoazHLQgwUC0UQcDfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.66.0", + "@typescript-eslint/tsconfig-utils": "8.66.0", + "@typescript-eslint/types": "8.66.0", + "@typescript-eslint/visitor-keys": "8.66.0", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/project-service": { + "version": "8.66.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.66.0.tgz", + "integrity": "sha512-7MthGPTt4BP69lSryqpqq8HQqxuzynssckL/jyDyk3+TNMQ3y2jFWkptCrktWvBrP+EH787Nl5N5Qpw7WZg+5g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.66.0", + "@typescript-eslint/types": "^8.66.0", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.66.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.66.0.tgz", + "integrity": "sha512-9D5gLYZG4rOjcoag8MQ/fWI8WqA9wcPDyOGyWtWFhvM1lHRbliqUSPIY5J3zqCU1tvSwzXxnnjhQhz5Ne7mJ4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/utils": { + "version": "8.66.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.66.0.tgz", + "integrity": "sha512-jasearZPolBw5NJNYGMwxzHMF83niVWmMU1VdHzG1CyfI2VS7f7nZltnKtHcg20hW+7Uo5GfK4MeDPoU3qI8EA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.66.0", + "@typescript-eslint/types": "8.66.0", + "@typescript-eslint/typescript-estree": "8.66.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/typescript-eslint/node_modules/ignore": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.6.tgz", + "integrity": "sha512-BAg6QkE8W+TuQLrrw0Ugr7HegXduRuuj8/ti2kSOc+jz1dmx8/WNcjr6XGnq5YpDWxFwwaavqD0+jIUOKelTsw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, "node_modules/undici-types": { "version": "8.3.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.3.0.tgz", diff --git a/vscode-extension/package.json b/vscode-extension/package.json index 51031ab58..4c372af59 100644 --- a/vscode-extension/package.json +++ b/vscode-extension/package.json @@ -19,6 +19,7 @@ { "command": "vibecli.connectDaemon", "title": "VibeCLI: Connect to Daemon" }, { "command": "vibecli.startDaemon", "title": "VibeCLI: Start Daemon" }, { "command": "vibecli.inlineEdit", "title": "VibeCLI: Inline Edit (selection)" }, + { "command": "vibecli.ghostComplete", "title": "VibeCLI: Inline Completion at Cursor" }, { "command": "vibecli.viewJobs", "title": "VibeCLI: View Background Jobs" }, { "command": "vibecli.sendSelection", "title": "VibeCLI: Send Selection to Agent" }, { "command": "vibecli.dictate", "title": "VibeCLI: Dictate (voice input)" }, @@ -66,6 +67,12 @@ "key": "ctrl+shift+enter", "mac": "cmd+shift+enter", "when": "editorHasSelection" + }, + { + "command": "vibecli.ghostComplete", + "key": "alt+\\", + "mac": "alt+\\", + "when": "editorTextFocus" } ], "configuration": { @@ -104,6 +111,11 @@ ], "description": "AI provider to use. Must be a provider the daemon can build (matches vibe-ai::catalog / create_provider). Set the provider's API key via the app or the daemon; ollama needs no key." }, + "vibecli.model": { + "type": "string", + "default": "", + "description": "Model id for vibecli.provider (e.g. \"claude-opus-5\", \"gpt-5\"). The daemon only honours the provider override when a model is set too — leave this empty to use whichever provider and model the daemon itself was started with." + }, "vibecli.approval": { "type": "string", "default": "suggest", diff --git a/vscode-extension/src/api-client.ts b/vscode-extension/src/api-client.ts index f37e5790d..1e2244860 100644 --- a/vscode-extension/src/api-client.ts +++ b/vscode-extension/src/api-client.ts @@ -234,6 +234,24 @@ export interface IndexBuildResponse { path: string; } +export interface GhostCompleteRequest { + filePath: string; + language: string; + /** Text before the cursor, already windowed by the caller. */ + prefix: string; + /** Text after the cursor, already windowed by the caller. */ + suffix: string; + provider?: string; + model?: string; +} + +export interface GhostCompleteResponse { + completion: string; + model_name: string; + /** The daemon clipped the model's answer at its line cap. */ + truncated: boolean; +} + export class VibeCLIClient { private baseUrl: string; private explicitToken?: string; @@ -280,6 +298,31 @@ export class VibeCLIClient { } } + /** + * Explicit-trigger inline completion for the cursor position. + * + * Called only from `ghost-text.ts`, which gates on VS Code's *Invoke* + * trigger kind. There is no automatic caller — see that file's header. + */ + async ghostComplete(req: GhostCompleteRequest): Promise<GhostCompleteResponse> { + const res = await this.authedFetch(`${this.baseUrl}/v1/ghost/complete`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + file_path: req.filePath, + language: req.language, + prefix: req.prefix, + suffix: req.suffix, + provider: req.provider, + model: req.model, + }), + }); + if (!res.ok) { + throw new Error(`Inline completion failed: ${res.status} ${await res.text()}`); + } + return await res.json() as GhostCompleteResponse; + } + /** Single-turn chat (non-streaming). */ async chat(messages: ChatMessage[]): Promise<string> { const res = await this.authedFetch(`${this.baseUrl}/chat`, { diff --git a/vscode-extension/src/extension.ts b/vscode-extension/src/extension.ts index 6671445e3..f2d7fc637 100644 --- a/vscode-extension/src/extension.ts +++ b/vscode-extension/src/extension.ts @@ -16,6 +16,7 @@ import { type JobRecord, } from './api-client'; import { GoalsTreeProvider, GoalTreeItem } from './goals-tree'; +import { registerGhostText } from './ghost-text'; import { gatePromptSubmission } from './hook-executor'; import { startRecording, type RecordingHandle } from './voice-capture'; @@ -42,6 +43,17 @@ export async function activate(context: vscode.ExtensionContext): Promise<void> // Try connecting to the daemon await tryConnect(); + // Ghost text — explicit-trigger inline completion (alt+\). Registers its + // own command; the provider answers only VS Code's Invoke trigger kind, so + // typing never issues a request. See ghost-text.ts. + registerGhostText(context, { + client: () => (daemonConnected ? client : null), + getProvider: () => vscode.workspace.getConfiguration('vibecli').get<string>('provider', ''), + getModel: () => vscode.workspace.getConfiguration('vibecli').get<string>('model', ''), + showError: (message) => vscode.window.showWarningMessage(`VibeCLI: ${message}`), + showInfo: (message) => vscode.window.setStatusBarMessage(`VibeCLI: ${message}`, 5000), + }); + // Register commands context.subscriptions.push( vscode.commands.registerCommand('vibecli.connectDaemon', handleConnectDaemon), diff --git a/vscode-extension/src/ghost-text.ts b/vscode-extension/src/ghost-text.ts new file mode 100644 index 000000000..dd400b465 --- /dev/null +++ b/vscode-extension/src/ghost-text.ts @@ -0,0 +1,188 @@ +/** + * Ghost text — explicit-trigger inline completion for VS Code. + * + * # The gate + * + * VS Code calls an inline completion provider for both automatic (typing) and + * explicit (user gesture) triggers. This provider answers only the explicit + * one. That check is the entire reason this surface is not the keystroke-driven + * one removed in `5a7eef7c`, so it does not get relaxed. + * + * **The enum is inverted between our two editors.** VS Code has + * `InlineCompletionTriggerKind = { Invoke: 0, Automatic: 1 }`; Monaco has + * `{ Automatic: 0, Explicit: 1 }`. The same names carry opposite numbers, so a + * literal `=== 1` copied from the VibeCoder provider (`src/lib/ghostText.ts`) + * would gate on exactly the wrong half and fire on every keystroke. Always + * compare against the named member. + * + * There is no debounce timer and no edit-history buffer here — one request per + * user gesture, carrying only the window around the cursor. + */ +import * as vscode from 'vscode'; +import { VibeCLIClient } from './api-client'; + +/** Lines of context sent before the cursor. */ +export const PREFIX_LINES = 160; +/** Lines of context sent after the cursor. */ +export const SUFFIX_LINES = 60; + +/** The bounded window around a cursor position. */ +export interface ContextWindow { + prefix: string; + suffix: string; + /** Text between the cursor and the end of its line. */ + restOfLine: string; +} + +/** + * The slice of `vscode.TextDocument` this module needs. Narrowed so the pure + * helpers below can be tested without a live editor. + */ +export interface WindowableDocument { + lineCount: number; + getText(range?: vscode.Range): string; + lineAt(line: number): { range: vscode.Range; text: string }; +} + +/** Slice the bounded window around the cursor. */ +export function windowContext( + document: WindowableDocument, + position: vscode.Position, + makeRange: (sl: number, sc: number, el: number, ec: number) => vscode.Range, +): ContextWindow { + const firstLine = Math.max(0, position.line - PREFIX_LINES); + const lastLine = Math.min(document.lineCount - 1, position.line + SUFFIX_LINES); + const lineEnd = document.lineAt(position.line).range.end; + const lastLineEnd = document.lineAt(lastLine).range.end; + + return { + prefix: document.getText( + makeRange(firstLine, 0, position.line, position.character), + ), + suffix: document.getText( + makeRange(position.line, position.character, lastLine, lastLineEnd.character), + ), + restOfLine: document.getText( + makeRange(position.line, position.character, position.line, lineEnd.character), + ), + }; +} + +/** + * Constrain a completion so it renders correctly at the cursor. + * + * A multi-line suggestion cannot be shown when real code follows the cursor on + * the same line, so it is clipped to its first line. Returns `null` when + * nothing renderable remains. + */ +export function fitCompletionToLine( + completion: string, + restOfLine: string, +): string | null { + if (completion.length === 0) return null; + if (restOfLine.trim().length === 0) return completion; + + const firstLine = completion.split('\n')[0]; + return firstLine.trim().length === 0 ? null : firstLine; +} + +/** What the provider needs from the extension host. */ +export interface GhostTextDeps { + client: () => VibeCLIClient | null; + /** `vibecli.provider` / `vibecli.model` settings, empty when unset. */ + getProvider: () => string; + getModel: () => string; + showError: (message: string) => void; + showInfo: (message: string) => void; +} + +/** + * Build the provider. Exported separately from `registerGhostText` so tests + * can drive `provideInlineCompletionItems` directly. + */ +export function createGhostTextProvider( + deps: GhostTextDeps, +): vscode.InlineCompletionItemProvider { + return { + async provideInlineCompletionItems(document, position, context, token) { + // ── The gate. Read this file's header before changing it. ── + if (context.triggerKind !== vscode.InlineCompletionTriggerKind.Invoke) { + return undefined; + } + + const client = deps.client(); + if (!client) { + deps.showError('Not connected to the VibeCLI daemon.'); + return undefined; + } + + const { prefix, suffix, restOfLine } = windowContext( + document, + position, + (sl, sc, el, ec) => new vscode.Range(sl, sc, el, ec), + ); + + let response; + try { + response = await client.ghostComplete({ + filePath: document.uri.fsPath, + language: document.languageId, + prefix, + suffix, + provider: deps.getProvider() || undefined, + model: deps.getModel() || undefined, + }); + } catch (error) { + deps.showError( + error instanceof Error ? error.message : String(error), + ); + return undefined; + } + + if (token.isCancellationRequested) return undefined; + + // An empty completion is the model declining, not a failure. + const text = fitCompletionToLine(response.completion, restOfLine); + if (text === null) return undefined; + + if (response.truncated) { + // The cap lives in `vibe_ai::ghost`; don't restate the number, it + // would go stale silently. + deps.showInfo('Suggestion was clipped — accept it and re-trigger for more.'); + } + + return [ + new vscode.InlineCompletionItem( + text, + new vscode.Range(position, position), + ), + ]; + }, + }; +} + +/** + * Register the provider for every file and wire the explicit trigger command. + * + * Registering on `'*'` is safe precisely because of the trigger gate: the + * provider is consulted constantly and answers only when asked. + */ +export function registerGhostText( + context: vscode.ExtensionContext, + deps: GhostTextDeps, +): void { + context.subscriptions.push( + vscode.languages.registerInlineCompletionItemProvider( + { pattern: '**' }, + createGhostTextProvider(deps), + ), + vscode.commands.registerCommand('vibecli.ghostComplete', async () => { + // The built-in trigger action is what reaches the provider with + // `Invoke`; calling the provider ourselves would bypass VS Code's + // ghost-text rendering and its Tab-to-accept binding. + await vscode.commands.executeCommand( + 'editor.action.inlineSuggest.trigger', + ); + }), + ); +}