Skip to content

fix(shell-integration): resync all three packaged copies with src - #169

Merged
amirlehmam merged 1 commit into
amirlehmam:masterfrom
stlindenau:fix/packaged-shell-integration
Aug 14, 2026
Merged

fix(shell-integration): resync all three packaged copies with src#169
amirlehmam merged 1 commit into
amirlehmam:masterfrom
stlindenau:fix/packaged-shell-integration

Conversation

@stlindenau

@stlindenau stlindenau commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Second of the three splits of #166. One commit, three files, all of it generated from master's own src/ — nothing is picked from the feature branch.

The drift

resources/shell-integration/ is a checked-in copy of src/shell-integration/ with nothing keeping it in step. All three had drifted:

file behind src/
wmux-bash-integration.sh missing the wmux() function
wmux-cmd-integration.cmd missing chcp 65001
wmux-powershell-integration.ps1 19 insertions, 65 deletions

The PowerShell one is the interesting case. Its copy predates #72, so Send-WmuxMessage sends V1 lines with no auth <token> prefix — and pipe-server.ts:157 rejects every V1 command but ping without one. Anything running that copy reports no cwd, no git branch, no shell state and no PR; the pipe answers unauthorized and the integration has no way to notice. It also predates the UTF-8 console setup, the wmux function, deferring the PR-poll job off the first-prompt critical path, and WMUX_STARTUP_COMMANDS (#32).

After this, diff -r src/shell-integration resources/shell-integration is empty.

Before you weigh how urgent this is

No release path reads these files. electron-builder.json:50 maps src/shell-integrationshell-integration, step 7 of the release process copies src/shell-integration/* into staging, and getShellIntegrationPath() falls back to src/shell-integration in dev. A packaged wmux has always run the fresh source — none of the breakage above ever reached a released install.

What does read resources/shell-integration/ is anything consuming wmux out of a repo checkout, which is how the drift surfaced: our devcontainer integration sources the bash copy from there directly. Same shape as resources/cli/wmux.js, which is 1519 diff lines behind a build of master's own src/ for the same reason — a duplicate with no enforcement. (Details in #168.)

The follow-up worth picking

Resyncing fixes today's drift and guarantees tomorrow's. Two ways out, happy to send either as a fourth PR — just say which:

  1. A CI step that fails when resources/ does not match a fresh copy/build, covering the shell scripts and resources/cli/*.js together.
  2. Delete resources/shell-integration/ and point checkout consumers at src/shell-integration/, since nothing wmux ships or runs reads it.

The second is the smaller repo but breaks any external consumer already on the old path, so it is your call rather than mine. (We are such a consumer and would happily move.)

Verification

  • bash -n clean on the packaged .sh; sourced in a plain bash with no error, wmux resolves as a function.
  • Full suite on this branch: 6 failed, 988 passed, 2 skipped — byte-identical to the same run on a detached master worktree with the same node_modules. No test reads these files, so that is expected; it confirms nothing regressed.
  • The .ps1 and .cmd want a native Windows check, which is yours. The specific thing to look for: with the old packaged copy the sidebar shows no cwd or branch in a PowerShell pane launched from a repo checkout, and with this one it should.
  • A manual run of npm run test in git bash on windows showed no failing tests (Claude has been running in a devcontainer on WSL to do the heavy lifting of this PR)

🤖 Generated with Claude Code

`resources/shell-integration/` is a checked-in copy of `src/shell-integration/`
that nothing keeps in step, and all three files had drifted:

  wmux-bash-integration.sh         missing the `wmux()` function
  wmux-cmd-integration.cmd         missing `chcp 65001`
  wmux-powershell-integration.ps1  19 insertions, 65 deletions behind

The PowerShell one is the interesting case. Its copy predates issue amirlehmam#72, so
`Send-WmuxMessage` sends V1 lines with no `auth <token> ` prefix — and
pipe-server.ts rejects every V1 command but `ping` without one. Anything running
that copy reports no cwd, no git branch, no shell state, no PR: the pipe answers
`unauthorized` and the integration has no way to notice. It also predates the
UTF-8 console setup, the `wmux` function, deferring the PR-poll job off the
first-prompt critical path, and `WMUX_STARTUP_COMMANDS` (issue amirlehmam#32).

Copied from master's own `src/`, so the three files are now byte-identical to
their sources; `diff -r src/shell-integration resources/shell-integration` is
empty.

Worth knowing before deciding how much this matters: no release path reads these
files. electron-builder's extraResources maps `src/shell-integration` →
`shell-integration`, step 7 of the release process copies `src/shell-integration/*`
into the staging dir, and `getShellIntegrationPath()` falls back to
`src/shell-integration` in dev. So a packaged wmux has always run the fresh
source, and none of the breakage above ever reached a released install.

What does read `resources/shell-integration/` is anything consuming wmux out of
a repo checkout — which is how the drift was found; a devcontainer integration
sources the bash copy from there. That makes this the same shape as
`resources/cli/wmux.js`, which is 1519 diff lines behind a build of master's own
`src/` for the same reason: a duplicate with no enforcement.

Resyncing fixes today's drift and guarantees tomorrow's. Two ways out, both
happy to send as a follow-up — say which you prefer:

  - a CI step that fails when `resources/` does not match a fresh copy/build,
    covering the shell scripts and `resources/cli/*.js` together; or
  - delete `resources/shell-integration/` outright and point checkout consumers
    at `src/shell-integration/`, since nothing wmux ships or runs reads it.

The second is the smaller repo, but it breaks any external consumer already
reading the old path, so it is your call rather than mine.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@amirlehmam
amirlehmam merged commit ec90ed5 into amirlehmam:master Aug 14, 2026
amirlehmam added a commit that referenced this pull request Aug 14, 2026
Both PRs ended by asking which direction I wanted for the checked-in
duplicates. This is the answer: keep them, and check them.

resources/shell-integration/ is a copy of src/shell-integration/, and
resources/cli/*.js a copy of the tsc output in dist/cli/. Nothing kept
either in step and both had rotted — the packaged PowerShell integration
predated the pipe's auth gate, so it sent V1 lines with no token and every
report was rejected into a void with no way to notice, and the CLI copy
was ~1700 diff lines behind its own source.

That is exactly #137, where a second copy of the app icon went stale for
three releases: a duplicate with no enforcement is not a duplicate, it is
a time bomb. #169 resynced today's drift; this stops tomorrow's.

Deletion was the other option offered and is not taken here. Nothing wmux
ships reads either directory (extraResources maps src/shell-integration
and dist/cli), but external consumers read them out of a repo checkout —
which is how the drift was found — and removing a path they depend on is
not something to do silently in a patch release.

Split by what each half costs:

- npm test covers shell-integration, which needs no build, so the check
  gates a release through CI's existing test step.
- npm run verify:resources covers the CLI artifacts too, and CI runs it
  after build:main, which is what makes dist/cli exist. It skips loudly
  rather than passing quietly when dist/ is absent — a check that
  silently does nothing reads as coverage it is not providing.

resources/cli/*.js is regenerated here to make the invariant true.
@stlindenau
stlindenau deleted the fix/packaged-shell-integration branch August 14, 2026 14:35
@amirlehmam

Copy link
Copy Markdown
Owner

Merged in 1.0.1.

The PowerShell one is worse than "drifted", and I want it recorded properly: that copy predates #72, so Send-WmuxMessage sent V1 lines with no auth <token> prefix, and pipe-server.ts rejects every V1 command but ping without one. So anything running it reported no cwd, no git branch, no shell state and no PR — and the failure is completely silent in both directions. The pipe writes unauthorized back into a socket the integration never reads, and the integration's own error handling is catch { } with the comment "Silently ignore pipe errors". Two independent reasons nobody would ever see a message.

Confirmed on the merged file:

if ($env:WMUX_PIPE_TOKEN) { $Message = "auth $($env:WMUX_PIPE_TOKEN) $Message" }   # line 24
if ($pipeToken) { $msg = "auth $pipeToken $msg" }                                  # line 123

Both call sites, and diff -r src/shell-integration resources/shell-integration is empty on Windows.

You were right to lead with "no release path reads these files" rather than let me over-rate the severity. electron-builder.json:50 maps src/shell-integration, step 7 of the release process copies from src/, and getShellIntegrationPath()'s dev fallback resolves to src/ too. No released install ever ran the broken copy. It's a checkout-consumer bug, which is a smaller blast radius and a real one.

The follow-up, decided

You offered a CI step or deletion. I took the CI step, in this release, so you don't need to send it:

  • tests/unit/resources-sync.test.ts — byte-compares the directories, newline-normalised. No build needed, so it runs on every npm test, which is what gates a release in CI.
  • npm run verify:resources — the same check plus resources/cli/*.js against dist/cli/*.js, wired into CI after build:main.

One test in there names the auth prefix directly rather than leaving it to the byte comparison, because that's the property whose absence was invisible. A future edit that drops it should fail as "the PowerShell integration no longer authenticates", not as "the files differ".

Not deletion, though it's the tidier repo. Nothing wmux ships reads either directory, but you read them out of a checkout and you're unlikely to be the only one; removing a path external consumers depend on isn't a thing to do silently in a patch release. If you'd still rather move, say so — I'll deprecate the path in a minor and drop it in the one after, and you get to be the reason it's safe.

Worth saying plainly: this is #137 again. That was a second copy of the app icon going stale for three releases, and the lesson written down at the time was that a duplicate has exactly one source. I resynced that one and didn't add a check, so the same failure just recurred in two other directories. It's checked now.

What I verified, and what I didn't

Verified: diff -r empty, bash -n clean, both auth call sites present, full suite green at 1021 passing / 86 files, and verify:resources fails as intended when I deliberately perturb a file.

Not verified: your specific end-to-end check — a PowerShell pane launched from a repo checkout showing cwd and branch in the sidebar. The packaged copy is now byte-identical to src/, and src/ is what every released install has always run and does work, so the inference is short. But it is an inference, and you should treat it as one if you're relying on it.

Thanks — the auth-token finding is the kind of thing that stays broken for years because nothing ever raises its hand.

amirlehmam pushed a commit that referenced this pull request Aug 14, 2026
Claude Code increasingly runs in a Linux devcontainer while wmux runs on
Windows. Nothing in that container can open \\.\pipe\wmux, so the CLI, the
hooks and the shell integration all failed silently: no cwd, no git branch,
and a sidebar stuck on "Running" forever.

The bridge from issue #78 is most of the answer already — it just could not
reach the pipe from where it needed to run. Three pieces close the gap:

* connectTransport() learns npiperelay.exe, so `wmux bridge` can run INSIDE
  WSL2 and still reach the Windows pipe over interop. That placement is the
  security property: 0.0.0.0 there is the WSL2 namespace, reachable from
  containers on the host and not from the LAN, with no firewall rule. AF_VSOCK,
  a Windows-side listener and cross-boundary Unix sockets were tried first and
  are documented as rejected in the code.
* The bridge keeps relays warm and tears down half-close-aware. Spawning
  npiperelay measures ~7s on an AV-scanned corporate host, and destroying both
  sides on either 'close' killed the frame of any client that writes and hangs
  up — which is every Claude Code hook. Deadlines gain a floor on the slow
  transports for the same reason; the 5s default sat below the round-trip, so
  calls that had already succeeded were reported as timeouts.
* `wmux raw-v1` gives the bash integration a way to send its V1 lines through
  the CLI's transport instead of a temp file it cannot write to, and
  wmux-hook.js gets the same TCP branch.

report_startup_command is new and rides the same path: a shell declares how to
bring its own surface back, stored per surface, so a restored pane re-enters
its container instead of coming up as a bare WSL prompt.

docs/DEVCONTAINER.md is the standalone setup — one binary, one command, two
environment variables, no vendor tooling.

Two things ride along that were separate commits in #166, because on current
master they have nothing to stand on their own for. The npiperelay lookup
splits PATH on path.delimiter and falls back to process.env.Path — the
Windows spelling — which only matters for the finder this commit introduces;
#168 landed the rest of that change and deliberately left this half behind.
And resources/shell-integration/wmux-bash-integration.sh is updated in step
with its source, which #169 plus the check in 42e3cca now require: the
packaged copy was resynced from a pre-bridge src/, so it has the `wmux` shim
but not the WMUX_REMOTE branch, and leaving it that way fails npm test.

Co-Authored-By: Claude <noreply@anthropic.com>
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.

2 participants