Conversation
Normalize Windows path strings before deriving host pipe names so the CLI, setup flow, and host runtime resolve the same endpoint. Improve named-pipe diagnostics and manual connectivity guidance to surface the profile, data dir, pipe path, and likely cause when ping fails. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Fixes native Windows host connectivity by making named-pipe identity stable across mixed \ and / path separators, and improves named-pipe connection diagnostics to aid troubleshooting.
Changes:
- Introduces shared Windows path normalization + named-pipe derivation helpers in
tabctl_shared. - Updates CLI setup/transport and host runtime to use shared normalization and pipe derivation for consistent endpoints.
- Improves Windows named-pipe connect error output and adds regression tests for mixed-separator behavior and diagnostics.
Reviewed changes
Copilot reviewed 7 out of 8 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| rust/crates/tabctl/src/cli/transport.rs | Uses shared pipe derivation; adds richer Windows pipe connect error formatting; normalizes resolved dirs. |
| rust/crates/tabctl/src/cli/setup.rs | Persists host_path/data_dir using platform-normalized strings; normalizes Windows registry/manifest paths. |
| rust/crates/tabctl/src/cli/local.rs | Adds connectivity troubleshooting guidance (including Windows-specific env var comparison). |
| rust/crates/tabctl/src/cli/impls.rs | Imports shared helpers and adds regression tests for Windows pipe resolution and diagnostics. |
| rust/crates/shared/src/lib.rs | Adds normalize_windows_path_string, path_to_platform_string, and windows_pipe_path helpers + tests. |
| rust/crates/shared/Cargo.toml | Adds sha2 dependency to support shared pipe hashing. |
| rust/crates/host/src/host_impl/runtime.rs | Normalizes env/registry-derived paths and uses shared pipe derivation for Windows. |
| rust/Cargo.lock | Records dependency update for tabctl-shared (sha2). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| fn windows_pipe_connect_error_includes_profile_data_dir_and_hint() { | ||
| let err = std::io::Error::from_raw_os_error(5); | ||
| let rendered = format_windows_pipe_connect_error( | ||
| Some("edge"), | ||
| r"C:\Users\tester\AppData\Local\tabctl\profiles\edge", | ||
| r"\\.\pipe\tabctl-test", | ||
| &err, | ||
| ); |
There was a problem hiding this comment.
The test calls format_windows_pipe_connect_error, but that helper is defined as a private function inside the transport module, so it won’t be accessible from this tests module (a parent module can’t access private items of a child module, and use transport::* won’t glob-import non-public items). This will fail to compile on Windows. Make the helper pub(super)/pub(crate) (optionally gated behind #[cfg(any(windows, test))]), or move the test into cli/transport.rs where it has access.
What
Fix native Windows host connectivity so mixed
\\and/path separators no longer cause the CLI and host runtime to derive different named-pipe endpoints.This PR also improves the Windows error text for named-pipe connect failures so it reports the resolved profile, data dir, pipe path, OS error code, and a likely cause.
Why
A reported Windows PowerShell failure showed
tabctl pingreturningaccess denied (5)when the generated host wrapper was started manually. The investigation confirmed that native Windowspinguses the named-pipe transport, not TCP auth-token validation, and uncovered a real path-identity bug: semantically identical Windows paths could hash to different pipe names if one side used\\and the other used/.How
tabctl-sharedhost_pathanddata_dirvalues during setupTesting
Validated locally on macOS:
cargo fmt --manifest-path rust/Cargo.toml --allnpm testnpm run test:integrationWindows local checkout test instructions
Please test from a native Windows PowerShell session using this branch from a local checkout, not a globally installed
tabctl.1. Checkout and build locally
From the repo root:
This builds the Rust workspace and produces the unpacked extension build in
dist/extension.2. Load the local extension build
Open
edge://extensionsorchrome://extensions, enable Developer mode, then Load unpacked and select:3. Run the local binary from the checkout
Use one of these options from the repo root so you are testing the branch build, not an already installed binary.
Option A: run via Cargo
Option B: run the built debug binary directly after
npm run buildIf testing Chrome instead of Edge, replace
--browser edgewith--browser chrome.4. Expected normal behavior
setupshould write the native host manifest, wrapper script, and profile registrationpingshould succeed without needing to run the wrapper manually5. If automatic startup still fails
Use the manual wrapper launch only as a diagnostic step:
tabctl-host.cmdwrapper manually from the same PowerShell/user contextor
.\rust\target\debug\tabctl.exe ping6. What to capture if it still fails
If
pingfails, please capture the full new error text.It should now include:
profiledata dirPlease also compare
TABCTL_PROFILE,TABCTL_CONFIG_DIR, andTABCTL_DATA_DIRbetween the wrapper environment and the CLI shell.If the failure is still a persistent
os error 5with matching profile/data-dir values, the next likely issue is named-pipe ACL/security behavior rather than auth-token handling.