Skip to content

spike(v4): evaluate Tauri 2 Studio shell feasibility - #25

Draft
YashasVM wants to merge 1 commit into
mainfrom
codex/spike-v4-tauri-studio
Draft

spike(v4): evaluate Tauri 2 Studio shell feasibility#25
YashasVM wants to merge 1 commit into
mainfrom
codex/spike-v4-tauri-studio

Conversation

@YashasVM

@YashasVM YashasVM commented Aug 2, 2026

Copy link
Copy Markdown
Owner

Summary

  • add a quarantined Tauri 2.11.5 + React/shadcn Windows Studio candidate with no C++ engine, OBS, codec, recording, or product-media code
  • add a separate user-SID-scoped named-pipe test service, bounded/versioned typed Rust bridge, simulated texture descriptors, and async Tauri command
  • publish raw release-process measurements, deployment/signing/WebView2 analysis, and an ADR that keeps V4-03 open

Evidence outcome

This PR does not select Tauri and does not claim the V4-03 gate is complete.

Measured across three release launches on the target HP Victus/i5-13420H/RTX 4050 host:

  • responsive window: 660.92–1122.53 ms
  • process-tree private bytes: 193,126,400–198,045,696
  • mean idle CPU: 0.369% of total logical CPU
  • mean three-step resize call sequence: 23.38 ms
  • Studio EXE: 3,320,832 bytes; Studio + fake service EXEs: 3,641,856 bytes

The typed Rust client and protected user-SID service tests pass, but the release GUI did not consume the standalone service in any measurement launch (0/3). That is recorded as FAIL, not a pass. Installed payload, post-reboot cold start, process-attributed GPU, real OS DPI switching, human Narrator, and real D3D11 shared-texture presentation are explicitly NOT_RUN with blockers.

Validation

  • python -m pytest -q — 40 passed
  • npm run build:web — pass
  • npm test — 2 passed
  • npm run test:a11y — 6 passed across browser device-scale 100/150/200%
  • npm audit --audit-level=high — 0 vulnerabilities
  • cargo fmt --check — pass
  • cargo test --workspace --all-targets — 2 passed
  • git diff --check — pass

The in-app Browser runtime failed to initialize (failed to write kernel assets), so rendered validation used the documented Playwright fallback. Browser scale is not claimed as Windows OS DPI evidence.

Architecture boundary

The spike remains under spikes/v4-tauri-studio and is absent from root CMake/product builds. JavaScript receives descriptors only, never D3D handle values. The ADR keeps provisional WinUI 3 and the original WinUI/Qt comparison unchanged pending real shared-texture evidence.

Summary by CodeRabbit

  • New Features

    • Added a Studio feasibility preview with connection status, preview cards, reconnect behavior, theme switching, accessibility labels, and responsive layouts.
    • Added a secured local service integration that provides typed preview snapshot data.
    • Added Windows packaging and release measurement support.
  • Documentation

    • Documented feasibility findings, deployment considerations, security constraints, and comparison criteria.
    • Recorded benchmark results and known validation gaps.
  • Tests

    • Added unit, accessibility, browser, keyboard, theme, and reduced-motion coverage.

@coderabbitai

coderabbitai Bot commented Aug 2, 2026

Copy link
Copy Markdown

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 264a88a7-014d-4496-aa4f-faebd2790a88

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • ✅ Review completed - (🔄 Check again to review again)

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

🧹 Nitpick comments (4)
spikes/v4-tauri-studio/vite.config.ts (1)

8-8: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Restrict client-exposed environment variables.

envPrefix makes every TAURI_ENV_... variable available to client-side code. If a developer or CI environment uses that prefix for a secret, the value can reach the WebView bundle. Keep this prefix only if all matching variables are explicitly non-sensitive. Otherwise, narrow it to approved public names.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@spikes/v4-tauri-studio/vite.config.ts` at line 8, Restrict the envPrefix
configuration in vite.config.ts so client-side code only receives explicitly
approved public environment variables; remove the broad TAURI_ENV_ prefix unless
every matching variable is guaranteed non-sensitive, and use a narrow allowlist
of required public names instead.
spikes/v4-tauri-studio/src-tauri/tauri.conf.json (1)

11-14: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add bundle.icon for the Windows NSIS bundle.

src-tauri/icons/icon.ico is already present, but tauri.conf.json omits bundle.icon; add it so the Windows bundle uses a branded app icon instead of relying on NSIS installer-icon defaults.

Proposed configuration
 "bundle": {
   "active": true,
   "targets": ["nsis"],
+  "icon": ["icons/icon.ico"],
   "windows": { "webviewInstallMode": { "type": "embedBootstrapper" }, "nsis": { "installMode": "currentUser" } }
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@spikes/v4-tauri-studio/src-tauri/tauri.conf.json` around lines 11 - 14, Add
the bundle.icon configuration within the existing bundle object in
tauri.conf.json, referencing the existing src-tauri/icons/icon.ico asset so the
Windows NSIS bundle uses the branded application icon.
spikes/v4-tauri-studio/src-tauri/src/lib.rs (1)

13-21: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Strengthen client-side pipe-name validation to match the actual current-user SID.

validate_bridge_config only checks that pipe starts with the literal prefix \\.\pipe\openstream-v4-studio-spike-S-1-. It does not confirm the SID suffix belongs to the process's own user. pipe-service.rs derives the real SID with current_user_sid() and compares it exactly (Line 111 in pipe-service.rs); the client should apply the same check instead of a format-only prefix match. The ADR for this spike calls out that "Same-user pipe squatting remains in the threat model," so tightening the client check is a reasonable, low-cost improvement even for this quarantined spike.

♻️ Suggested direction
-fn validate_bridge_config(pipe: String, nonce: String) -> Result<(String, String), String> {
-    if !pipe.starts_with(r"\\.\pipe\openstream-v4-studio-spike-S-1-") {
-        return Err("pipe name is not user-SID scoped".to_owned());
-    }
+fn validate_bridge_config(pipe: String, nonce: String, expected_sid: &str) -> Result<(String, String), String> {
+    let expected_pipe = format!(r"\\.\pipe\openstream-v4-studio-spike-{expected_sid}");
+    if pipe != expected_pipe {
+        return Err("pipe name does not match the current user SID".to_owned());
+    }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@spikes/v4-tauri-studio/src-tauri/src/lib.rs` around lines 13 - 21, Update
validate_bridge_config to derive the current user SID using the existing
current_user_sid mechanism from pipe-service.rs and require the pipe name to
match the exact expected user-scoped pipe format and SID, rather than only
checking the static prefix. Preserve the existing nonce length validation and
error-result behavior.
spikes/v4-tauri-studio/src-tauri/src/bin/pipe-service.rs (1)

135-136: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Bound server.connect().await with a timeout.

server.connect().await? waits indefinitely for a client. If the client never attaches — which appears to be exactly what happened in the recorded measurements (pipeServiceExitCode: null in every trial in measurements.jsonl) — this process hangs forever instead of exiting with a diagnosable error. Wrap the wait in tokio::time::timeout (mirroring the 2-second bound already used on the client side in lib.rs) so the service exits deterministically when no client connects.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@spikes/v4-tauri-studio/src-tauri/src/bin/pipe-service.rs` around lines 135 -
136, Wrap the server connection wait in the pipe service’s startup flow with
tokio::time::timeout, using the existing 2-second client-side timeout as the
bound. Update the error propagation around server.connect().await so a timeout
produces a diagnosable failure and the process exits deterministically when no
client connects.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@spikes/v4-tauri-studio/package.json`:
- Line 17: Update the `@tauri-apps/api` and `@tauri-apps/cli` dependency pins in
package.json to 2.11.5 to match the Rust tauri crate, then regenerate
package-lock.json so the resolved versions are consistent. If retaining older
versions intentionally, document that decision in a note instead.

In `@spikes/v4-tauri-studio/rust-toolchain.toml`:
- Around line 2-3: Update the rust-toolchain configuration alongside channel and
profile to explicitly include the rustfmt component, ensuring fresh
installations can run the required cargo fmt --check command without manual
setup.

In `@spikes/v4-tauri-studio/scripts/measure-release.ps1`:
- Around line 31-32: Update the payload measurement and Write-Row schema in the
release measurement script to report $studio and $service sizes separately as
studioExecutableBytes and pipeServiceExecutableBytes. Do not use the combined
value for studioExecutableBytes; if retaining the sum, expose it as
releasePayloadBytes and update the recorded evidence accordingly.
- Around line 19-29: Update the trial flow around the service readiness loop and
measurement block to verify that the service emitted READY and remains usable
before launching Studio; otherwise fail or record an explicitly invalid trial
instead of writing a normal measurement row. Wrap each trial in try/finally so
cleanup always stops the Studio process tree and $svc, including exceptions
during startup or measurement.

In `@spikes/v4-tauri-studio/src-tauri/src/bin/pipe-service.rs`:
- Around line 108-135: Redact the machine-specific SID from the READY output in
the pipe-service startup flow before printing it with println!("READY
{pipe_name}"), while preserving the pipe’s actual name for creation and
communication. Update the evidence-generation process so committed service
output does not retain the raw SID, including existing affected artifacts if
applicable.

In `@spikes/v4-tauri-studio/src-tauri/src/lib.rs`:
- Around line 52-74: The named-pipe handshake needs bounded retry and timeout
handling. In spikes/v4-tauri-studio/src-tauri/src/lib.rs:52-74, update
connect_pipe_service to retry ClientOptions::open for transient
ERROR_PIPE_BUSY/NotFound failures within the existing 2-second timeout, while
preserving immediate handling of other errors. In
spikes/v4-tauri-studio/src-tauri/src/bin/pipe-service.rs:135-136, wrap
server.connect().await in a timeout so the service exits when no client
connects, including the pipeServiceExitCode: null path.

In `@spikes/v4-tauri-studio/src-tauri/src/main.rs`:
- Around line 1-3: Add a crate-level Windows subsystem attribute at the top of
main.rs, gated to release builds, so the executable uses the windows subsystem
instead of opening a console while preserving the existing main function and
debug behavior.

In `@spikes/v4-tauri-studio/src/App.tsx`:
- Around line 17-27: Update the connection flow around connect and connectBridge
to use an async action that keeps pending true until the native invoke settles,
and guard against concurrent reconnect requests. Handle connection failures
explicitly by returning a distinct native-failure status from
connect_test_service, then render that status instead of treating unavailable
native service as ordinary Simulation.

---

Nitpick comments:
In `@spikes/v4-tauri-studio/src-tauri/src/bin/pipe-service.rs`:
- Around line 135-136: Wrap the server connection wait in the pipe service’s
startup flow with tokio::time::timeout, using the existing 2-second client-side
timeout as the bound. Update the error propagation around server.connect().await
so a timeout produces a diagnosable failure and the process exits
deterministically when no client connects.

In `@spikes/v4-tauri-studio/src-tauri/src/lib.rs`:
- Around line 13-21: Update validate_bridge_config to derive the current user
SID using the existing current_user_sid mechanism from pipe-service.rs and
require the pipe name to match the exact expected user-scoped pipe format and
SID, rather than only checking the static prefix. Preserve the existing nonce
length validation and error-result behavior.

In `@spikes/v4-tauri-studio/src-tauri/tauri.conf.json`:
- Around line 11-14: Add the bundle.icon configuration within the existing
bundle object in tauri.conf.json, referencing the existing
src-tauri/icons/icon.ico asset so the Windows NSIS bundle uses the branded
application icon.

In `@spikes/v4-tauri-studio/vite.config.ts`:
- Line 8: Restrict the envPrefix configuration in vite.config.ts so client-side
code only receives explicitly approved public environment variables; remove the
broad TAURI_ENV_ prefix unless every matching variable is guaranteed
non-sensitive, and use a narrow allowlist of required public names instead.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 08d874f2-551b-483e-8f98-930a6f36a0d6

📥 Commits

Reviewing files that changed from the base of the PR and between 6c65476 and 7cc5b0e.

⛔ Files ignored due to path filters (52)
  • spikes/v4-tauri-studio/package-lock.json is excluded by !**/package-lock.json
  • spikes/v4-tauri-studio/src-tauri/Cargo.lock is excluded by !**/*.lock
  • spikes/v4-tauri-studio/src-tauri/icons/128x128.png is excluded by !**/*.png
  • spikes/v4-tauri-studio/src-tauri/icons/128x128@2x.png is excluded by !**/*.png
  • spikes/v4-tauri-studio/src-tauri/icons/32x32.png is excluded by !**/*.png
  • spikes/v4-tauri-studio/src-tauri/icons/64x64.png is excluded by !**/*.png
  • spikes/v4-tauri-studio/src-tauri/icons/Square107x107Logo.png is excluded by !**/*.png
  • spikes/v4-tauri-studio/src-tauri/icons/Square142x142Logo.png is excluded by !**/*.png
  • spikes/v4-tauri-studio/src-tauri/icons/Square150x150Logo.png is excluded by !**/*.png
  • spikes/v4-tauri-studio/src-tauri/icons/Square284x284Logo.png is excluded by !**/*.png
  • spikes/v4-tauri-studio/src-tauri/icons/Square30x30Logo.png is excluded by !**/*.png
  • spikes/v4-tauri-studio/src-tauri/icons/Square310x310Logo.png is excluded by !**/*.png
  • spikes/v4-tauri-studio/src-tauri/icons/Square44x44Logo.png is excluded by !**/*.png
  • spikes/v4-tauri-studio/src-tauri/icons/Square71x71Logo.png is excluded by !**/*.png
  • spikes/v4-tauri-studio/src-tauri/icons/Square89x89Logo.png is excluded by !**/*.png
  • spikes/v4-tauri-studio/src-tauri/icons/StoreLogo.png is excluded by !**/*.png
  • spikes/v4-tauri-studio/src-tauri/icons/android/mipmap-hdpi/ic_launcher.png is excluded by !**/*.png
  • spikes/v4-tauri-studio/src-tauri/icons/android/mipmap-hdpi/ic_launcher_foreground.png is excluded by !**/*.png
  • spikes/v4-tauri-studio/src-tauri/icons/android/mipmap-hdpi/ic_launcher_round.png is excluded by !**/*.png
  • spikes/v4-tauri-studio/src-tauri/icons/android/mipmap-mdpi/ic_launcher.png is excluded by !**/*.png
  • spikes/v4-tauri-studio/src-tauri/icons/android/mipmap-mdpi/ic_launcher_foreground.png is excluded by !**/*.png
  • spikes/v4-tauri-studio/src-tauri/icons/android/mipmap-mdpi/ic_launcher_round.png is excluded by !**/*.png
  • spikes/v4-tauri-studio/src-tauri/icons/android/mipmap-xhdpi/ic_launcher.png is excluded by !**/*.png
  • spikes/v4-tauri-studio/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_foreground.png is excluded by !**/*.png
  • spikes/v4-tauri-studio/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_round.png is excluded by !**/*.png
  • spikes/v4-tauri-studio/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher.png is excluded by !**/*.png
  • spikes/v4-tauri-studio/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_foreground.png is excluded by !**/*.png
  • spikes/v4-tauri-studio/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_round.png is excluded by !**/*.png
  • spikes/v4-tauri-studio/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher.png is excluded by !**/*.png
  • spikes/v4-tauri-studio/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_foreground.png is excluded by !**/*.png
  • spikes/v4-tauri-studio/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_round.png is excluded by !**/*.png
  • spikes/v4-tauri-studio/src-tauri/icons/icon.ico is excluded by !**/*.ico
  • spikes/v4-tauri-studio/src-tauri/icons/icon.png is excluded by !**/*.png
  • spikes/v4-tauri-studio/src-tauri/icons/ios/AppIcon-20x20@1x.png is excluded by !**/*.png
  • spikes/v4-tauri-studio/src-tauri/icons/ios/AppIcon-20x20@2x-1.png is excluded by !**/*.png
  • spikes/v4-tauri-studio/src-tauri/icons/ios/AppIcon-20x20@2x.png is excluded by !**/*.png
  • spikes/v4-tauri-studio/src-tauri/icons/ios/AppIcon-20x20@3x.png is excluded by !**/*.png
  • spikes/v4-tauri-studio/src-tauri/icons/ios/AppIcon-29x29@1x.png is excluded by !**/*.png
  • spikes/v4-tauri-studio/src-tauri/icons/ios/AppIcon-29x29@2x-1.png is excluded by !**/*.png
  • spikes/v4-tauri-studio/src-tauri/icons/ios/AppIcon-29x29@2x.png is excluded by !**/*.png
  • spikes/v4-tauri-studio/src-tauri/icons/ios/AppIcon-29x29@3x.png is excluded by !**/*.png
  • spikes/v4-tauri-studio/src-tauri/icons/ios/AppIcon-40x40@1x.png is excluded by !**/*.png
  • spikes/v4-tauri-studio/src-tauri/icons/ios/AppIcon-40x40@2x-1.png is excluded by !**/*.png
  • spikes/v4-tauri-studio/src-tauri/icons/ios/AppIcon-40x40@2x.png is excluded by !**/*.png
  • spikes/v4-tauri-studio/src-tauri/icons/ios/AppIcon-40x40@3x.png is excluded by !**/*.png
  • spikes/v4-tauri-studio/src-tauri/icons/ios/AppIcon-512@2x.png is excluded by !**/*.png
  • spikes/v4-tauri-studio/src-tauri/icons/ios/AppIcon-60x60@2x.png is excluded by !**/*.png
  • spikes/v4-tauri-studio/src-tauri/icons/ios/AppIcon-60x60@3x.png is excluded by !**/*.png
  • spikes/v4-tauri-studio/src-tauri/icons/ios/AppIcon-76x76@1x.png is excluded by !**/*.png
  • spikes/v4-tauri-studio/src-tauri/icons/ios/AppIcon-76x76@2x.png is excluded by !**/*.png
  • spikes/v4-tauri-studio/src-tauri/icons/ios/AppIcon-83.5x83.5@2x.png is excluded by !**/*.png
  • spikes/v4-tauri-studio/src-tauri/icons/spike-icon.svg is excluded by !**/*.svg
📒 Files selected for processing (41)
  • .gitignore
  • docs/adr/0001-tauri-2-studio-feasibility.md
  • docs/evidence/v4-03-tauri-studio.md
  • spikes/v4-tauri-studio/README.md
  • spikes/v4-tauri-studio/components.json
  • spikes/v4-tauri-studio/index.html
  • spikes/v4-tauri-studio/package.json
  • spikes/v4-tauri-studio/playwright.config.ts
  • spikes/v4-tauri-studio/postcss.config.js
  • spikes/v4-tauri-studio/results/2026-08-02-target/measurements.jsonl
  • spikes/v4-tauri-studio/results/2026-08-02-target/service-1.err.txt
  • spikes/v4-tauri-studio/results/2026-08-02-target/service-1.out.txt
  • spikes/v4-tauri-studio/results/2026-08-02-target/service-2.err.txt
  • spikes/v4-tauri-studio/results/2026-08-02-target/service-2.out.txt
  • spikes/v4-tauri-studio/results/2026-08-02-target/service-3.err.txt
  • spikes/v4-tauri-studio/results/2026-08-02-target/service-3.out.txt
  • spikes/v4-tauri-studio/results/2026-08-02-target/summary.json
  • spikes/v4-tauri-studio/rust-toolchain.toml
  • spikes/v4-tauri-studio/scripts/measure-release.ps1
  • spikes/v4-tauri-studio/scripts/summarize-results.ps1
  • spikes/v4-tauri-studio/src-tauri/Cargo.toml
  • spikes/v4-tauri-studio/src-tauri/build.rs
  • spikes/v4-tauri-studio/src-tauri/capabilities/main.json
  • spikes/v4-tauri-studio/src-tauri/icons/icon.icns
  • spikes/v4-tauri-studio/src-tauri/src/bin/pipe-service.rs
  • spikes/v4-tauri-studio/src-tauri/src/lib.rs
  • spikes/v4-tauri-studio/src-tauri/src/main.rs
  • spikes/v4-tauri-studio/src-tauri/src/protocol.rs
  • spikes/v4-tauri-studio/src-tauri/tauri.conf.json
  • spikes/v4-tauri-studio/src/App.test.tsx
  • spikes/v4-tauri-studio/src/App.tsx
  • spikes/v4-tauri-studio/src/bridge.ts
  • spikes/v4-tauri-studio/src/components/ui/button.tsx
  • spikes/v4-tauri-studio/src/lib/utils.ts
  • spikes/v4-tauri-studio/src/main.tsx
  • spikes/v4-tauri-studio/src/styles.css
  • spikes/v4-tauri-studio/tailwind.config.ts
  • spikes/v4-tauri-studio/tests/studio.spec.ts
  • spikes/v4-tauri-studio/tsconfig.app.json
  • spikes/v4-tauri-studio/tsconfig.json
  • spikes/v4-tauri-studio/vite.config.ts

},
"dependencies": {
"@radix-ui/react-slot": "1.2.3",
"@tauri-apps/api": "2.11.1",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n '`@tauri-apps/`(api|cli)|\btauri(-build)?\b' \
  spikes/v4-tauri-studio/package.json \
  spikes/v4-tauri-studio/package-lock.json \
  spikes/v4-tauri-studio/src-tauri/Cargo.toml \
  spikes/v4-tauri-studio/src-tauri/Cargo.lock

Repository: YashasVM/OpenStream

Length of output: 7688


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== package files =="
cat -n spikes/v4-tauri-studio/package.json

echo
echo "== Rust dependency declarations =="
cat -n spikes/v4-tauri-studio/src-tauri/Cargo.toml

echo
echo "== Rust lockfile Tauri crates =="
python3 - <<'PY'
from pathlib import Path
p = Path('spikes/v4-tauri-studio/src-tauri/Cargo.lock')
text = p.read_text()
for crate in ['tauri', 'tauri-build', 'tauri-codegen', 'tauri-utils', 'tauri-runtime', 'tauri-runtime-wry', 'tauri-macros', 'tauri-winres']:
    idx = text.find(f'name = "{crate}"\n')
    if idx == -1:
        print(f'{crate}: not found')
        continue
    start = text.rfind('[['[:idx], 0, idx)
    pkg = text[start:idx+300]
    print(pkg)
PY

Repository: YashasVM/OpenStream

Length of output: 5506


Align the Tauri 2.11.5 pins.

The Rust crate target is tauri = "=2.11.5", but the Node packages remain pinned to older patches: @tauri-apps/api is 2.11.1 and @tauri-apps/cli is 2.11.4. Update these matches in package.json, regenerate package-lock.json, and add a note if the older packages are intentional.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@spikes/v4-tauri-studio/package.json` at line 17, Update the `@tauri-apps/api`
and `@tauri-apps/cli` dependency pins in package.json to 2.11.5 to match the Rust
tauri crate, then regenerate package-lock.json so the resolved versions are
consistent. If retaining older versions intentionally, document that decision in
a note instead.

Comment on lines +2 to +3
channel = "1.88.0"
profile = "minimal"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Changed files/stat:"
git diff --stat || true

echo
echo "Locate rust-toolchain.toml files:"
fd -a 'rust-toolchain\.toml$' . || true

echo
echo "Relevant rust-toolchain.toml contents:"
while IFS= read -r f; do
  echo "--- $f"
  cat -n "$f"
done < <(git ls-files '**/rust-toolchain.toml' 'rust-toolchain.toml')

echo
echo "Search for fmt/rustfmt references and toolchain/component mentions:"
rg -n --hidden --glob '!target/**' 'cargo\s+fmt|rustfmt|--check|components|rustup|toolchain' . || true

echo
echo "Check repository files for shell scripts/setup that might install components:"
fd -a -t f . | sed 's#^\./##' | rg '/(\.github|scripts|setup|justfile|Taskfile|Makefile|README|.*\.md)$|\.sh$|\.bat$|\.ps1$' | sort | sed -n '1,200p' || true

Repository: YashasVM/OpenStream

Length of output: 367


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Changed files/stat:"
git diff --stat || true

echo
echo "Changed/added rust-toolchain.toml if any:"
git diff --diff-filter=A --name-only HEAD^..HEAD -- | rg '(^|/)rust-toolchain\.toml$' || true
git diff HEAD^..HEAD -- 'spikes/v4-tauri-studio/rust-toolchain.toml' || true

echo
echo "Relevant rust-toolchain.toml contents:" for f in $(git ls-files 'spikes/v4-tauri-studio/rust-toolchain.toml' 'rust-toolchain.toml'); do echo "--- $f"; cat -n "$f"; done

echo
echo "Search for fmt/rustfmt references and toolchain/component mentions:"
rg -n --hidden --glob '!target/**' 'cargo\s+fmt|rustfmt|--check|components|rustup|toolchain' . || true

echo
echo "Repository setup documentation/scripts candidates:"
git ls-files | rg '(\.github|scripts|setup|justfile|Taskfile|Makefile|README|.*\.md|\.sh$|\.bat$|\.ps1$|pyproject\.toml|package\.json)$' | sort | sed -n '1,200p' || true

Repository: YashasVM/OpenStream

Length of output: 635


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Relevant rust-toolchain.toml contents:"
for f in $(git ls-files 'spikes/v4-tauri-studio/rust-toolchain.toml' 'rust-toolchain.toml'); do
  echo "--- $f"
  cat -n "$f"
done

echo
echo "Search for fmt/rustfmt references and toolchain/component mentions:"
rg -n --hidden --glob '!target/**' 'cargo\s+fmt|rustfmt|--check|components|rustup|toolchain' . || true

echo
echo "Repository setup documentation/scripts candidates:"
git ls-files | rg '(\.github|scripts|setup|justfile|Taskfile|Makefile|README|.*\.md|\.sh$|\.bat$|\.ps1$|pyproject\.toml|package\.json)$' | sort | sed -n '1,200p' || true

echo
echo "Rust documentation/source availability (static cargo config files if present):"
if command -v cargo >/dev/null 2>&1; then
  echo "cargo path: $(command -v cargo)"
  cargo --version || true
  rustc --version || || true
fi

Repository: YashasVM/OpenStream

Length of output: 3258


🌐 Web query:

rustup profiles default minimal rustfmt component not included

💡 Result:

The rustup minimal profile intentionally does not include rustfmt [1][2]. The minimal profile is designed to include only the essential components required to provide a working Rust compiler: rustc, cargo, and the Rust standard library (rust-std) [1][3]. In contrast, the default profile includes these three components along with rust-docs, rustfmt, and clippy [1][3]. If you are encountering rustfmt despite selecting the minimal profile, consider the following possibilities: 1. Pre-existing environment: In some environments (such as certain CI/CD images), a default toolchain may already be installed or pre-configured with extra components, which can persist if you attempt to "update" the toolchain without clearing previous settings [4][5]. 2. Manual installation: If you require rustfmt after installing with the minimal profile, you can manually add it to your toolchain at any time by running: rustup component add rustfmt [2] [3] To verify your current profile setting or ensure a fresh installation, you can use rustup set profile minimal or perform a clean installation after clearing any existing.rustup and.cargo directories [5][6].

Citations:


Pin rustfmt with the stated cargo fmt --check requirement.

slices/v4-tauri-studio/rust-toolchain.toml uses the minimal profile, which does not include rustfmt. A fresh toolchain install cannot run cargo fmt --check unless rustfmt is explicitly added. Add components = ["rustfmt"], or document and enforce the manual rustup component add rustfmt step.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@spikes/v4-tauri-studio/rust-toolchain.toml` around lines 2 - 3, Update the
rust-toolchain configuration alongside channel and profile to explicitly include
the rustfmt component, ensuring fresh installations can run the required cargo
fmt --check command without manual setup.

Comment on lines +19 to +29
$svc=Start-Process $service -RedirectStandardOutput $stdout -RedirectStandardError $stderr -PassThru -WindowStyle Hidden
$wait=[Diagnostics.Stopwatch]::StartNew(); while($wait.ElapsedMilliseconds-lt3000 -and !(Select-String -Quiet -LiteralPath $stdout -Pattern '^READY ' -ErrorAction SilentlyContinue)){Start-Sleep -Milliseconds 25}
$clock=[Diagnostics.Stopwatch]::StartNew(); $app=Start-Process $studio -PassThru
while($clock.ElapsedMilliseconds-lt10000){$app.Refresh();if($app.MainWindowHandle-ne0 -and $app.Responding){break};Start-Sleep -Milliseconds 10}; $ready=$clock.Elapsed.TotalMilliseconds
if($app.MainWindowHandle-eq0){Stop-Process $app.Id -Force;throw "Studio did not expose a responsive window"}
Wait-Process $svc.Id -Timeout 5 -ErrorAction SilentlyContinue; $svc.Refresh(); Start-Sleep -Seconds $IdleSeconds
$tree=Get-Tree $app.Id; $before=Get-Process -Id $tree -ErrorAction SilentlyContinue; $cpu0=($before|Measure-Object CPU -Sum).Sum; Start-Sleep 2
$after=Get-Process -Id $tree -ErrorAction SilentlyContinue; $cpu1=($after|Measure-Object CPU -Sum).Sum
$resize=[Diagnostics.Stopwatch]::StartNew();foreach($size in @(@(900,620),@(1400,900),@(1180,760))){[WindowProbe]::MoveWindow($app.MainWindowHandle,40,40,$size[0],$size[1],$true)|Out-Null};$resize.Stop()
Write-Row ([ordered]@{schemaVersion=1;trial=$trial;timestamp=(Get-Date).ToUniversalTime().ToString("o");startKind=if($trial-eq1){"cold-unprimed"}else{"warm"};launchResponsiveMs=[math]::Round($ready,2);pipeServiceExitCode=if($svc.HasExited){$svc.ExitCode}else{$null};processCount=$after.Count;privateBytes=($after|Measure-Object PrivateMemorySize64 -Sum).Sum;workingSetBytes=($after|Measure-Object WorkingSet64 -Sum).Sum;idleCpuPercent=[math]::Round((($cpu1-$cpu0)/2/[Environment]::ProcessorCount*100),3);resizeSequenceMs=[math]::Round($resize.Elapsed.TotalMilliseconds,2);pids=$tree})
foreach($id in ($tree|Sort-Object -Descending)){Stop-Process $id -Force -ErrorAction SilentlyContinue};Stop-Process $svc.Id -Force -ErrorAction SilentlyContinue

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Fail or mark a trial invalid when the service is not ready.

The readiness loop at Line 20 has no result check. The script starts Studio after a timeout even when the service failed to bind or exited. It can then emit a normal launch row without a usable bridge. An exception before Line 29 also leaves the service process running.

After the wait, require READY before starting Studio. Wrap each trial in try/finally and always stop the app tree and $svc. If the purpose is to retain failed evidence, write an explicit invalid trial result instead of a normal measurement row.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@spikes/v4-tauri-studio/scripts/measure-release.ps1` around lines 19 - 29,
Update the trial flow around the service readiness loop and measurement block to
verify that the service emitted READY and remains usable before launching
Studio; otherwise fail or record an explicitly invalid trial instead of writing
a normal measurement row. Wrap each trial in try/finally so cleanup always stops
the Studio process tree and $svc, including exceptions during startup or
measurement.

Comment on lines +31 to +32
$payload=(Get-Item $studio,$service|Measure-Object Length -Sum).Sum; $wv=(Get-ItemProperty 'HKLM:\SOFTWARE\WOW6432Node\Microsoft\EdgeUpdate\Clients\*' -ErrorAction SilentlyContinue|Where-Object name -Like '*WebView2*'|Select-Object -First 1)
Write-Row ([ordered]@{schemaVersion=1;kind="environment";commit=(git -C $root rev-parse HEAD);os=[Environment]::OSVersion.VersionString;logicalProcessors=[Environment]::ProcessorCount;rust=(rustc --version);node=(node --version);webView2Version=$wv.pv;webViewInstallMode="embedBootstrapper";releaseExecutableBytes=$payload;gpuCounter="NOT_RUN: no reliable process-attributed GPU counter in harness";osDpi="NOT_RUN: Windows scale change needs interactive sign-out";narrator="NOT_RUN: requires human judgment"})

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Report Studio and service binary sizes separately.

releaseExecutableBytes sums $studio and $service. It cannot support the PR claim that this value is the Studio executable size. Emit separate studioExecutableBytes and pipeServiceExecutableBytes fields. If needed, add a distinct combined releasePayloadBytes field and update recorded evidence.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@spikes/v4-tauri-studio/scripts/measure-release.ps1` around lines 31 - 32,
Update the payload measurement and Write-Row schema in the release measurement
script to report $studio and $service sizes separately as studioExecutableBytes
and pipeServiceExecutableBytes. Do not use the combined value for
studioExecutableBytes; if retaining the sum, expose it as releasePayloadBytes
and update the recorded evidence accordingly.

Comment on lines +108 to +135
let expected_pipe = format!(r"\\.\pipe\openstream-v4-studio-spike-{sid}");
let pipe_name =
env::var("OPENSTREAM_TAURI_TEST_PIPE").unwrap_or_else(|_| expected_pipe.clone());
if pipe_name != expected_pipe {
return Err(io::Error::new(
io::ErrorKind::PermissionDenied,
"pipe name must contain the current user SID",
));
}
let nonce = env::var("OPENSTREAM_TAURI_TEST_NONCE").map_err(|_| {
io::Error::new(
io::ErrorKind::InvalidInput,
"OPENSTREAM_TAURI_TEST_NONCE missing",
)
})?;
if nonce.len() < 32 || nonce.len() > 128 {
return Err(io::Error::new(io::ErrorKind::InvalidInput, "nonce length"));
}
let (_descriptor, mut attrs) = user_only_security(&sid)?;
let server = unsafe {
ServerOptions::new()
.first_pipe_instance(true)
.create_with_security_attributes_raw(
&pipe_name,
(&mut attrs as *mut SECURITY_ATTRIBUTES).cast(),
)?
};
println!("READY {pipe_name}");

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Pipe name (including the real Windows SID) is printed to stdout and persisted into committed evidence.

expected_pipe/pipe_name embed the current process's Windows SID, and println!("READY {pipe_name}") writes it to stdout. This exact string, including the full SID S-1-5-21-399773274-1772005713-2252464672-1001, is captured verbatim in results/2026-08-02-target/service-1.out.txt, service-2.out.txt, and service-3.out.txt, which are committed to the repository. A Windows SID is a persistent per-machine/per-account identifier; committing it as evidence ties the artifact to a specific developer machine indefinitely. Consider redacting the SID suffix before printing (or excluding raw service stdout from committed evidence) in future measurement runs.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@spikes/v4-tauri-studio/src-tauri/src/bin/pipe-service.rs` around lines 108 -
135, Redact the machine-specific SID from the READY output in the pipe-service
startup flow before printing it with println!("READY {pipe_name}"), while
preserving the pipe’s actual name for creation and communication. Update the
evidence-generation process so committed service output does not retain the raw
SID, including existing affected artifacts if applicable.

Comment on lines +52 to +74
async fn connect_pipe_service(pipe_name: String, nonce: String) -> BridgeStatus {
let result = timeout(Duration::from_secs(2), async {
let mut pipe = ClientOptions::new().open(&pipe_name)?;
let request = HelloRequest {
protocol_version: PROTOCOL_VERSION,
request_id: uuid::Uuid::new_v4().to_string(),
nonce,
};
let encoded = serde_json::to_vec(&request).map_err(io::Error::other)?;
write_frame(&mut pipe, &encoded).await?;
let response: HelloResponse =
serde_json::from_slice(&read_frame(&mut pipe).await?).map_err(io::Error::other)?;
if response.protocol_version != PROTOCOL_VERSION
|| response.request_id != request.request_id
{
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"protocol/request mismatch",
));
}
Ok::<_, io::Error>(response.snapshot)
})
.await;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Repo files matching relevant names:"
git ls-files | rg 'spikes/v4-tauri-studio/src-tauri/(src/lib\.rs|src/bin/pipe-service\.rs)|package\.json|measurements|summary' || true

echo
echo "lib.rs outline:"
ast-grep outline spikes/v4-tauri-studio/src-tauri/src/lib.rs --view compact || true

echo
echo "lib.rs relevant lines:"
nl -ba spikes/v4-tauri-studio/src-tauri/src/lib.rs | sed -n '1,130p'

echo
echo "pipe-service outline:"
ast-grep outline spikes/v4-tauri-studio/src-tauri/src/bin/pipe-service.rs --view compact || true

echo
echo "pipe-service relevant lines around connect:"
nl -ba spikes/v4-tauri-studio/src-tauri/src/bin/pipe-service.rs | sed -n '1,220p'

echo
echo "Search for named errors / timeouts around pipe/client/server:"
rg -n "ClientOptions|connect\\(|connect_pipe_service|ERROR_PIPE_BUSY|NotFound|timeout|measurements|summary|pipeConnectionsPassed|pipeServiceExitCode" -S --glob '!target/**' --glob '!**/dist/**' .

Repository: YashasVM/OpenStream

Length of output: 714


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Rust source relevant lines:"
awk '{ printf "%6d\t%s\n", NR, $0 }' spikes/v4-tauri-studio/src-tauri/src/lib.rs | sed -n '1,140p'

echo
awk '{ printf "%6d\t%s\n", NR, $0 }' spikes/v4-tauri-studio/src-tauri/src/bin/pipe-service.rs | sed -n '1,220p'

echo
echo "Search for named errors / timeouts around pipe/client/server:"
rg -n "ClientOptions|connect\\(|connect_pipe_service|ERROR_PIPE_BUSY|NotFound|timeout|measurements|summary|pipeConnectionsPassed|pipeServiceExitCode" -S --glob '!target/**' --glob '!**/dist/**' .

echo
echo "Relevant result snippets:"
if [ -f spikes/v4-tauri-studio/results/2026-08-02-target/measurements.jsonl ]; then
  awk '{ printf "%s\n", $0 }' spikes/v4-tauri-studio/results/2026-08-02-target/measurements.jsonl | sed -n '1,20p'
fi
if [ -f spikes/v4-tauri-studio/results/2026-08-02-target/summary.json ]; then
  awk '{ printf "%s\n", $0 }' spikes/v4-tauri-studio/results/2026-08-02-target/summary.json | sed -n '1,80p'
fi

Repository: YashasVM/OpenStream

Length of output: 33326


🌐 Web query:

Tokio named pipe ClientOptions open retry on ERROR_PIPE_BUSY Windows named_pipe documentation

💡 Result:

When using tokio::net::windows::named_pipe::ClientOptions to open a named pipe on Windows, you must manually implement a retry loop if the pipe is busy [1][2]. The Tokio library does not automatically retry for you [1][3]. When ClientOptions::open is called, it may return an error with the raw OS error code ERROR_PIPE_BUSY (defined in windows_sys::Win32::Foundation) [1][3]. This indicates that the pipe exists, but all instances are currently busy [1][2]. The idiomatic approach is to catch this specific error and sleep for a short duration before retrying [1][4]. The following example demonstrates the standard pattern for implementing this retry loop [1][3]: use std::time::Duration; use tokio::net::windows::named_pipe::ClientOptions; use tokio::time; use windows_sys::Win32::Foundation::ERROR_PIPE_BUSY; const PIPE_NAME: &str = r"\.\pipe\mynamedpipe"; let client = loop { match ClientOptions::new.open(PIPE_NAME) { Ok(client) => break client, // Check for ERROR_PIPE_BUSY and retry Err(e) if e.raw_os_error == Some(ERROR_PIPE_BUSY as i32) =>, Err(e) => return Err(e), } time::sleep(Duration::from_millis(50)).await; }; This manual retry mechanism mirrors the behavior required when using the underlying Windows API function CreateFile, which also returns ERROR_PIPE_BUSY when all pipe instances are occupied [5]. In such C/C++ scenarios, developers typically use WaitNamedPipe to handle the waiting, whereas in the Tokio ecosystem, the asynchronous loop approach is preferred to remain non-blocking [1][5].

Citations:


Add bounded retry and timeout handling to the named-pipe handshake. connect_pipe_service opens the pipe once and treats ERROR_PIPE_BUSY/NotFound as a failed handshake, while pipe-service.rs accepts clients with server.connect().await and can hang until no client attaches. Retry the client open on these transient errors inside the 2-second timeout, and add a timeout around the service server.connect().await so it exits for pipeServiceExitCode: null instead of waiting forever.

📍 Affects 2 files
  • spikes/v4-tauri-studio/src-tauri/src/lib.rs#L52-L74 (this comment)
  • spikes/v4-tauri-studio/src-tauri/src/bin/pipe-service.rs#L135-L136
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@spikes/v4-tauri-studio/src-tauri/src/lib.rs` around lines 52 - 74, The
named-pipe handshake needs bounded retry and timeout handling. In
spikes/v4-tauri-studio/src-tauri/src/lib.rs:52-74, update connect_pipe_service
to retry ClientOptions::open for transient ERROR_PIPE_BUSY/NotFound failures
within the existing 2-second timeout, while preserving immediate handling of
other errors. In
spikes/v4-tauri-studio/src-tauri/src/bin/pipe-service.rs:135-136, wrap
server.connect().await in a timeout so the service exits when no client
connects, including the pipeServiceExitCode: null path.

Comment on lines +1 to +3
fn main() {
openstream_tauri_studio_spike_lib::run()
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== target files ==="
fd -a 'main\.rs$|Cargo\.toml$|Cargo\.lock$|tauri\.conf|tauri.conf' . | sed 's#^\./##' | head -100

echo
echo "=== main.rs ==="
file="$(fd 'main\.rs$' spikes/v4-tauri-studio/src-tauri/src 2>/dev/null | head -1 || true)"
if [ -n "$file" ]; then
  cat -n "$file"
fi

echo
echo "=== windows_subsystem occurrences ==="
rg -n 'windows_subsystem|cfg_attr|tauri-build|build\.rs' . -g '*.rs' -g 'Cargo.toml' -g 'tauri.conf*' 2>/dev/null || true

echo
echo "=== package/release scripts mentions ==="
rg -n 'tauri build|cargo build|build' . -g '*.toml' -g '*.sh' -g '*.ps1' -g '*.bat' -g '*.js' -g '*.json' 2>/dev/null | head -200

Repository: YashasVM/OpenStream

Length of output: 11285


🌐 Web query:

Tauri 2 Cargo.toml windows_subsystem windows release build tauri-build default

💡 Result:

In Tauri 2, the windows_subsystem attribute is not configured in Cargo.toml [1]. Instead, it is a Rust attribute placed at the top of your main.rs file [2][3]. To prevent an additional console window from appearing when your application runs on Windows in release mode, include the following directive at the very top of your src-tauri/src/main.rs: #![cfg_attr(all(not(debug_assertions), target_os = "windows"), windows_subsystem = "windows")] This ensures that the console is hidden only during release builds (when debug_assertions are disabled) [2][4]. During development, the console remains visible to allow for logging and debugging [5]. Regarding the other components mentioned: 1. tauri-build: This is a build dependency used by Tauri, but it is not where you configure the windows_subsystem [6][1]. You typically define it in Cargo.toml under [build-dependencies] if you need custom build logic, but it does not control the subsystem attribute [1]. 2. Default Configuration: Configuration for your Tauri app (like bundle settings, windows, and permissions) is handled in tauri.conf.json (or Tauri.toml) [7][8]. 3. Release Build: Ensure you are running cargo tauri build (or npm run tauri build) to generate a production-ready release binary, as running via dev commands will not apply these release-specific optimizations [5]. If you still see a console window, verify that you have properly rebuilt the application in the target/release directory [2][5].

Citations:


🌐 Web query:

Rust windows_subsystem attribute Windows console GUI subsystem documentation

💡 Result:

In Rust, the windows_subsystem attribute is a crate-level attribute used to specify the Windows subsystem to link against when compiling for a Windows target [1][2]. This attribute controls whether the operating system creates a console window when the application starts [1][3]. Syntax and Usage The attribute is applied at the root of the crate (typically in main.rs or lib.rs) using the following syntax [1]: #![windows_subsystem = "windows"] Accepted values are: - "console": The default value [1]. A console process will be attached to an existing console if one is available; otherwise, a new console window is created [1]. - "windows": Commonly used for GUI applications that should run detached from any existing console, preventing a console window from appearing upon startup [1][3]. Key Technical Details - Crate-Level Only: The attribute must be applied to the crate root [1]. - Duplicate Handling: Only the first occurrence of this attribute has an effect; the compiler lints against subsequent uses [1]. - Target Platform: The attribute is ignored on non-Windows targets and non-binary crate types [1]. - Initialization: The attribute handles the necessary linker configuration, such as setting the entry point, ensuring that Rust's standard library initialization correctly handles the difference between standard entry points and the WinMain entry point expected by Windows for GUI applications [4][3]. When using the "windows" subsystem, applications effectively detach from the console [1]. If an application requires the ability to output to a console in some scenarios but not others, it often requires more complex logic, such as using a launcher application or programmatically attaching to a console using Windows APIs, as the subsystem choice is fixed at compile time [5][6].

Citations:


Suppress the Windows console in release builds.

The release executable for this Tauri app runs through main.rs with the default console subsystem, so Windows can show a console window alongside the GUI. Add a release-only crate-level subsystem attribute at the top of the file.

Proposed fix
+#![cfg_attr(all(not(debug_assertions), target_os = "windows"), windows_subsystem = "windows")]
+
 fn main() {
     openstream_tauri_studio_spike_lib::run()
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
fn main() {
openstream_tauri_studio_spike_lib::run()
}
#![cfg_attr(all(not(debug_assertions), target_os = "windows"), windows_subsystem = "windows")]
fn main() {
openstream_tauri_studio_spike_lib::run()
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@spikes/v4-tauri-studio/src-tauri/src/main.rs` around lines 1 - 3, Add a
crate-level Windows subsystem attribute at the top of main.rs, gated to release
builds, so the executable uses the windows subsystem instead of opening a
console while preserving the existing main function and debug behavior.

Comment on lines +17 to +27
const [pending, startTransition] = useTransition();
const connect = () => startTransition(() => { void connectBridge().then(setStatus); });
useEffect(connect, []);
useEffect(() => { document.documentElement.classList.toggle("dark", dark); }, [dark]);
const previews = status.snapshot?.previews ?? [];
return <main>
<header><div><p className="product">OpenStream Studio</p><h1>Windows shell feasibility</h1></div><div className="actions">
<Button variant="outline" onClick={() => setDark(value => !value)} aria-label={`Use ${dark ? "light" : "dark"} theme`}>{dark ? <Sun aria-hidden="true" /> : <Moon aria-hidden="true" />} Theme</Button>
<Button onClick={connect} disabled={pending}>{pending ? <RefreshCw className="spin" aria-hidden="true" /> : <PlugZap aria-hidden="true" />} Reconnect</Button>
</div></header>
<section className="statusbar" aria-live="polite"><strong>{status.connected ? "Connected" : "Simulation"}</strong><span>{status.detail}</span><code>{status.pipeName}</code></section>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

In React 19.2, does startTransitionkeepisPendingtrue for asynchronous work only when its callback returns a Promise or is declaredasync?

💡 Result:

In React 19, startTransition (whether standalone or from useTransition) supports passing an async function, which allows React to automatically track the isPending state during asynchronous operations [1][2][3]. When you pass an async function to startTransition, React treats the transition as pending from the moment it is called until the async function completes and all resulting state updates are committed [4][1][5]. The isPending flag remains true for the duration of the entire async callback, including any awaited work performed within it [4][2]. It is important to note the following: * Automatic tracking applies specifically to the async function passed to startTransition [1]. * State updates that occur after an await within the callback may not be automatically included in the transition if React loses the execution context [5][6]. To ensure subsequent state updates are grouped into the ongoing transition, they must be explicitly wrapped in another startTransition call [4][6]. * The isPending flag is only available via the useTransition hook [4][7][2]. The standalone startTransition function does not provide a way to track the pending state [7][2].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Tracked files:"
git ls-files | rg '(^|/)App\.tsx$|package\.json$|status|pipe-service|types' | sed -n '1,200p'

echo
echo "App.tsx outline:"
file="$(git ls-files | rg '(^|/)spikes/v4-tauri-studio/src/App\.tsx$' | head -n1 || true)"
if [ -n "$file" ]; then
  wc -l "$file"
  sed -n '1,220p' "$file"
fi

echo
echo "Package React versions:"
for f in $(git ls-files | rg '(^|/)package\.json$'); do
  echo "--- $f"
  python3 - <<PY "$f"
import json, sys
p=sys.argv[1]
try:
    data=json.load(open(p))
except Exception as e:
    print("ERR", e)
    raise SystemExit
deps={**data.get("dependencies",{}), **data.get("devDependencies",{}), **data.get("peerDependencies",{}), **data.get("optionalDependencies",{})}
for name in ("react", "`@types/react`", "typescript"):
    if name in deps:
        print(name, deps[name])
PY
done

echo
echo "Connect bridge definitions/usages:"
rg -n "connectBridge|setStatus|status\.|class\s+status|type\s+Status|interface\s+Status|pipe-service|pipeName|Test service|simulation|Simulation|Unavailable|unavailable" -S .

Repository: YashasVM/OpenStream

Length of output: 9861


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "bridge.ts:"
sed -n '1,220p' spikes/v4-tauri-studio/src/bridge.ts

echo
echo "pipe-service.rs connection path:"
sed -n '1,240p' spikes/v4-tauri-studio/src-tauri/src/bin/pipe-service.rs

echo
echo "BridgeStatus callers:"
rg -n "BridgeStatus|connected:|pipeName:|detail:" spikes/v4-tauri-studio/src-tauri spikes/v4-tauri-studio/src -S

Repository: YashasVM/OpenStream

Length of output: 9581


Keep the native connection request pending and handle failures.

void connectBridge().then(setStatus) clears pending before invoke() settles, so Reconnect can restart while the first native call is still active. Also, connect_test_service returns { connected: false, pipeName: "simulation" } on any failure, which still renders “Simulation” without surfacing an unavailable native service. Use an async Action for _pending_, guard concurrent requests, and return a distinct native-failure status.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@spikes/v4-tauri-studio/src/App.tsx` around lines 17 - 27, Update the
connection flow around connect and connectBridge to use an async action that
keeps pending true until the native invoke settles, and guard against concurrent
reconnect requests. Handle connection failures explicitly by returning a
distinct native-failure status from connect_test_service, then render that
status instead of treating unavailable native service as ordinary Simulation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant