From ea1ab098ea9d298c54a6c46729530c28ef439a31 Mon Sep 17 00:00:00 2001 From: Ammar Date: Thu, 20 Aug 2026 11:41:49 -0500 Subject: [PATCH 1/2] =?UTF-8?q?=F0=9F=A4=96=20fix:=20publish=20npm=20packa?= =?UTF-8?q?ge=20as=20@coder/shux?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the canonical npm package to the Coder scope while retaining the mux forwarding package and CLI alias. --- _Generated with `mux` • Model: `openai:gpt-5.6-sol` • Thinking: `xhigh` • Cost: `$11.36`_ --- .github/workflows/_npm-publish.yml | 30 ++++++---- .github/workflows/auto-cleanup.yml | 2 +- .github/workflows/pr.yml | 16 ++++-- .github/workflows/publish-npm.yml | 2 +- Makefile | 6 +- README.md | 5 +- bun.lock | 2 +- docs/guides/github-actions.mdx | 4 +- docs/install.mdx | 6 +- docs/reference/cli.mdx | 8 +-- docs/reference/mux-compatibility.mdx | 2 +- package.json | 8 +-- packages/mux-compat/README.md | 6 +- packages/mux-compat/bin/mux.js | 4 +- packages/mux-compat/package.json | 4 +- scripts/generate-npm-shrinkwrap.sh | 2 +- scripts/pack-npm-package.sh | 27 +++++++++ scripts/set-package-version.js | 2 +- scripts/smoke-test-mux-compat.sh | 53 +++++++++++++++++ scripts/smoke-test.sh | 4 +- src/common/compat/productIdentity.test.ts | 57 +++++++++++++++---- .../builtInSkillContent.generated.ts | 20 +++---- 22 files changed, 200 insertions(+), 70 deletions(-) create mode 100755 scripts/pack-npm-package.sh create mode 100755 scripts/smoke-test-mux-compat.sh diff --git a/.github/workflows/_npm-publish.yml b/.github/workflows/_npm-publish.yml index 67c2364b25f..742063b5a5a 100644 --- a/.github/workflows/_npm-publish.yml +++ b/.github/workflows/_npm-publish.yml @@ -4,12 +4,14 @@ name: NPM Publish (Reusable) # Called by publish-npm.yml (the OIDC-trusted caller). # # OIDC TRUSTED PUBLISHING SETUP (on npmjs.com): -# For each package (shux, mux, @coder/mux-chat-components): +# New packages must be published manually once before npm allows trusted publisher setup. +# For each package (@coder/shux, mux, @coder/mux-chat-components): # 1. Go to package settings → Trusted Publisher → GitHub Actions # 2. Configure: # - Owner: coder # - Repository: mux # - Workflow filename: publish-npm.yml (the caller, NOT this reusable) +# - Allowed action: npm publish # - Environment: (leave blank) on: @@ -91,7 +93,7 @@ jobs: echo "version=${NPM_VERSION}" >> "$GITHUB_OUTPUT" echo "tag=${NPM_TAG}" >> "$GITHUB_OUTPUT" - # Keep the canonical shux package and legacy mux forwarding package in lockstep. + # Keep the canonical @coder/shux package and legacy mux forwarding package in lockstep. node ./scripts/set-package-version.js "$NPM_VERSION" echo "Updated package versions to ${NPM_VERSION}" @@ -106,25 +108,26 @@ jobs: run: make build - name: Pack npm package for smoke test - run: npm pack - - - name: Find package tarball - id: find-tarball + id: pack run: | - # shellcheck disable=SC2012 # ls is fine here - known filename pattern in controlled directory - TARBALL=$(ls shux-*.tgz | head -1) + TARBALL=$(./scripts/pack-npm-package.sh) echo "tarball=$TARBALL" >> "$GITHUB_OUTPUT" echo "Found package: $TARBALL" - name: Run smoke test env: - PACKAGE_TARBALL: ${{ steps.find-tarball.outputs.tarball }} + PACKAGE_TARBALL: ${{ steps.pack.outputs.tarball }} SERVER_PORT: 3000 SERVER_HOST: localhost STARTUP_TIMEOUT: 30 run: | ./scripts/smoke-test.sh + - name: Run legacy mux forwarding package smoke test + env: + CANONICAL_TARBALL: ${{ steps.pack.outputs.tarball }} + run: ./scripts/smoke-test-mux-compat.sh + - name: Upload server logs on smoke test failure if: failure() uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 @@ -140,7 +143,7 @@ jobs: # don't respect shrinkwrap. Uses a different port to avoid conflicts. - name: Run smoke test (without shrinkwrap) env: - PACKAGE_TARBALL: ${{ steps.find-tarball.outputs.tarball }} + PACKAGE_TARBALL: ${{ steps.pack.outputs.tarball }} SERVER_PORT: 3001 SERVER_HOST: localhost STARTUP_TIMEOUT: 30 @@ -160,7 +163,12 @@ jobs: - name: Clean up tarball if: always() - run: rm -f shux-*.tgz + env: + PACKAGE_TARBALL: ${{ steps.pack.outputs.tarball }} + run: | + if [ -n "$PACKAGE_TARBALL" ]; then + rm -f "$PACKAGE_TARBALL" + fi - name: Check if version exists id: check-exists diff --git a/.github/workflows/auto-cleanup.yml b/.github/workflows/auto-cleanup.yml index 226b4648c8f..bdecb2293c8 100644 --- a/.github/workflows/auto-cleanup.yml +++ b/.github/workflows/auto-cleanup.yml @@ -70,7 +70,7 @@ jobs: ANTHROPIC_API_KEY: ${{ secrets.AUTO_CLEANUP_ANTHROPIC_API_KEY }} GH_TOKEN: ${{ steps.app-token.outputs.token }} run: | - bunx shux@next run \ + bunx @coder/shux@next run \ --model anthropic:claude-opus-5 \ --thinking xhigh \ < .github/prompts/auto-cleanup.md diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 9149af4bcfe..60613c8b91b 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -57,6 +57,8 @@ jobs: - 'tests/ui/**' config: - '.github/**' + - 'scripts/**' + - 'packages/mux-compat/**' - 'jest.config.cjs' - 'babel.config.cjs' - 'package.json' @@ -424,15 +426,19 @@ jobs: - uses: ./.github/actions/setup-mux - run: ./scripts/generate-npm-shrinkwrap.sh - run: make build - - run: npm pack + - name: Pack npm package + id: pack + run: echo "tarball=$(./scripts/pack-npm-package.sh)" >> "$GITHUB_OUTPUT" - env: + PACKAGE_TARBALL: ${{ steps.pack.outputs.tarball }} SERVER_PORT: 3001 SERVER_HOST: localhost STARTUP_TIMEOUT: 30 - run: | - # shellcheck disable=SC2012 # ls is fine here - known filename pattern in controlled directory - TARBALL=$(ls shux-*.tgz | head -1) - PACKAGE_TARBALL="$TARBALL" ./scripts/smoke-test.sh + run: ./scripts/smoke-test.sh + - name: Test legacy mux forwarding package + env: + CANONICAL_TARBALL: ${{ steps.pack.outputs.tarball }} + run: ./scripts/smoke-test-mux-compat.sh - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 if: failure() with: diff --git a/.github/workflows/publish-npm.yml b/.github/workflows/publish-npm.yml index c53b81d4083..9ef5713ee56 100644 --- a/.github/workflows/publish-npm.yml +++ b/.github/workflows/publish-npm.yml @@ -8,7 +8,7 @@ name: Publish to NPM # # IMPORTANT: This workflow's filename (publish-npm.yml) must match the OIDC # trusted publisher configured on npmjs.com. Do not rename without updating -# the npm trusted publisher settings for 'shux', 'mux', and +# the npm trusted publisher settings for '@coder/shux', 'mux', and # '@coder/mux-chat-components'. Publisher setup remains external. on: diff --git a/Makefile b/Makefile index c26e07866c0..e0794b0d6e0 100644 --- a/Makefile +++ b/Makefile @@ -431,10 +431,10 @@ test-coverage: ## Run tests with coverage smoke-test: build ## Run smoke test on npm package @echo "Building npm package tarball..." - @npm pack - @TARBALL=$$(ls shux-*.tgz | head -1); \ + @TARBALL=$$(./scripts/pack-npm-package.sh) || exit $$?; \ echo "Running smoke test on $$TARBALL..."; \ - PACKAGE_TARBALL="$$TARBALL" ./scripts/smoke-test.sh; \ + PACKAGE_TARBALL="$$TARBALL" ./scripts/smoke-test.sh && \ + CANONICAL_TARBALL="$$TARBALL" ./scripts/smoke-test-mux-compat.sh; \ EXIT_CODE=$$?; \ rm -f "$$TARBALL"; \ exit $$EXIT_CODE diff --git a/README.md b/README.md index ac1d6ba8ea0..af87dced4d2 100644 --- a/README.md +++ b/README.md @@ -13,13 +13,12 @@ [![Discord](https://img.shields.io/discord/1446553342699507907?logo=discord&label=Discord)](https://cdr.co/mux-discord) [![X (formerly Twitter)](https://img.shields.io/badge/Follow-%40codermux-black?logo=x)](https://x.com/codermux) - > [!IMPORTANT] > This project was renamed from Mux to Shux after Mux.com raised a trademark concern. “Mux” is a common technical abbreviation of “multiplexer” and we do not expect confusion between the projects, but chose to rename ours rather than spend more time on the dispute. “Shux” captures our reaction to the process and bears no other significance. -> -Shux is a desktop & browser application for parallel agentic development. It enables developers to plan and execute tasks with multiple AI agents on local or remote compute. +> +> Shux is a desktop & browser application for parallel agentic development. It enables developers to plan and execute tasks with multiple AI agents on local or remote compute.

Shux product demo

diff --git a/bun.lock b/bun.lock index 1e6e403f9cc..8b2482bb626 100644 --- a/bun.lock +++ b/bun.lock @@ -2,7 +2,7 @@ "lockfileVersion": 1, "workspaces": { "": { - "name": "shux", + "name": "@coder/shux", "dependencies": { "@agentclientprotocol/sdk": "^0.25.0", "@ai-sdk/amazon-bedrock": "^5.0.15", diff --git a/docs/guides/github-actions.mdx b/docs/guides/github-actions.mdx index 694f0956722..c21c8076c01 100644 --- a/docs/guides/github-actions.mdx +++ b/docs/guides/github-actions.mdx @@ -19,7 +19,7 @@ Here's a minimal example that runs Shux in a GitHub Action: env: ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: bunx shux run "Review this PR for critical issues. If any are found, exit with 1 to block merge." + run: bunx @coder/shux run "Review this PR for critical issues. If any are found, exit with 1 to block merge." ``` `shux run` supports agent-controlled exit codes, so the workflow step can fail when issues are found. @@ -115,7 +115,7 @@ jobs: ANTHROPIC_API_KEY: ${{ secrets.AUTO_CLEANUP_ANTHROPIC_API_KEY }} GH_TOKEN: ${{ steps.app-token.outputs.token }} run: | - bunx shux@next run \ + bunx @coder/shux@next run \ --model anthropic:claude-opus-5 \ --thinking xhigh \ < .github/prompts/auto-cleanup.md diff --git a/docs/install.mdx b/docs/install.mdx index 575e58dabc7..983dfe037d5 100644 --- a/docs/install.mdx +++ b/docs/install.mdx @@ -88,16 +88,16 @@ The Shux CLI can also be run directly via `npx` without installing the desktop a ```bash # Run agent tasks -npx shux run "Fix the failing tests" +npx @coder/shux run "Fix the failing tests" # Start the server for remote/mobile access -npx shux server --port 3000 +npx @coder/shux server --port 3000 ``` Or install globally: ```bash -npm install -g shux +npm install -g @coder/shux ``` The legacy `mux` package and command forward to the matching Shux release during the transition. See [Mux compatibility](/reference/mux-compatibility) for storage, environment-variable, and downgrade details. diff --git a/docs/reference/cli.mdx b/docs/reference/cli.mdx index 3fb0b4b4937..44fb8a0e054 100644 --- a/docs/reference/cli.mdx +++ b/docs/reference/cli.mdx @@ -27,14 +27,14 @@ The CLI is available via npm and can be run directly with `npx`: ```bash # Run without installing -npx shux run "Fix the failing tests" +npx @coder/shux run "Fix the failing tests" # Or install globally -npm install -g shux +npm install -g @coder/shux shux run "Fix the failing tests" ``` -Using `npx shux` is especially convenient for CI/CD pipelines where you don't want to manage a global installation. +Using `npx @coder/shux` is especially convenient for CI/CD pipelines where you don't want to manage a global installation. ## `shux run` @@ -42,7 +42,7 @@ Execute a one-off agent task: ```bash # Basic usage - run in current directory -npx shux run "Fix the failing tests" +npx @coder/shux run "Fix the failing tests" # Specify a directory shux run --dir /path/to/project "Add authentication" diff --git a/docs/reference/mux-compatibility.mdx b/docs/reference/mux-compatibility.mdx index f02c1212139..929b00437ae 100644 --- a/docs/reference/mux-compatibility.mdx +++ b/docs/reference/mux-compatibility.mdx @@ -10,7 +10,7 @@ Shux is the canonical product, package, command, protocol, and local data-direct | Surface | Canonical | Compatibility alias | | --------------------- | ---------------------------------- | --------------------------------------------------------- | -| npm package | `shux` | `mux` forwarding package | +| npm package | `@coder/shux` | `mux` forwarding package | | CLI | `shux` | `mux` | | Local data | `~/.shux` | `~/.mux` and older `~/.cmux` links | | Development data | `~/.shux-dev` | `~/.mux-dev` link | diff --git a/package.json b/package.json index 8cae898fa81..e2bcdc0de66 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "shux", + "name": "@coder/shux", "version": "0.28.2", "desktopName": "shux.desktop", "description": "shux - coding agent multiplexer", @@ -294,7 +294,7 @@ "zip" ], "icon": "build/icon.icns", - "artifactName": "${name}-${version}-${arch}.${ext}", + "artifactName": "shux-${version}-${arch}.${ext}", "hardenedRuntime": true, "gatekeeperAssess": false, "entitlements": "build/entitlements.mac.plist", @@ -305,7 +305,7 @@ "target": "AppImage", "category": "Development", "icon": "build/icons", - "artifactName": "${name}-${version}-${arch}.${ext}", + "artifactName": "shux-${version}-${arch}.${ext}", "desktop": { "StartupWMClass": "shux" } @@ -313,7 +313,7 @@ "win": { "target": "nsis", "icon": "build/icon.png", - "artifactName": "${name}-${version}-${arch}.${ext}", + "artifactName": "shux-${version}-${arch}.${ext}", "sign": "scripts/sign-windows.js", "signingHashAlgorithms": [ "sha256" diff --git a/packages/mux-compat/README.md b/packages/mux-compat/README.md index 2228771af91..99f3cc55acd 100644 --- a/packages/mux-compat/README.md +++ b/packages/mux-compat/README.md @@ -1,5 +1,5 @@ # mux compatibility package -`mux` is the legacy package and command name for [shux](https://github.com/coder/mux). -It forwards to the matching `shux` release so existing scripts keep working during -the rename. New installations should use `shux`. +`mux` is the legacy package and command name for [Shux](https://github.com/coder/mux). +It forwards to the matching `@coder/shux` release so existing scripts keep working during +the rename. New installations should use the `@coder/shux` package and `shux` command. diff --git a/packages/mux-compat/bin/mux.js b/packages/mux-compat/bin/mux.js index 17ea4fa2673..5aa9ab8651c 100755 --- a/packages/mux-compat/bin/mux.js +++ b/packages/mux-compat/bin/mux.js @@ -1,6 +1,6 @@ #!/usr/bin/env node // Keep the published `mux` package as a tiny forwarding boundary. The implementation -// stays entirely in `shux`, so the compatibility package can be retired without +// stays entirely in `@coder/shux`, so the compatibility package can be retired without // leaving duplicate CLI logic behind. -require("shux/dist/cli/index.js"); +require("@coder/shux/dist/cli/index.js"); diff --git a/packages/mux-compat/package.json b/packages/mux-compat/package.json index c3fd5da3107..82011a0ef1f 100644 --- a/packages/mux-compat/package.json +++ b/packages/mux-compat/package.json @@ -1,7 +1,7 @@ { "name": "mux", "version": "0.28.2", - "description": "Compatibility package forwarding the legacy mux command to shux", + "description": "Compatibility package forwarding the legacy mux command to @coder/shux", "bin": { "mux": "bin/mux.js" }, @@ -10,7 +10,7 @@ "README.md" ], "dependencies": { - "shux": "0.28.2" + "@coder/shux": "0.28.2" }, "repository": { "type": "git", diff --git a/scripts/generate-npm-shrinkwrap.sh b/scripts/generate-npm-shrinkwrap.sh index eff5403399b..92bb6a61e21 100755 --- a/scripts/generate-npm-shrinkwrap.sh +++ b/scripts/generate-npm-shrinkwrap.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# Generate npm-shrinkwrap.json for the root mux package. +# Generate npm-shrinkwrap.json for the canonical @coder/shux package. # We rely on npm's resolver and only include production dependencies. set -euo pipefail diff --git a/scripts/pack-npm-package.sh b/scripts/pack-npm-package.sh new file mode 100755 index 00000000000..c14035e7649 --- /dev/null +++ b/scripts/pack-npm-package.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash + +set -euo pipefail + +ROOT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) +cd "$ROOT_DIR" + +# Scoped package tarballs include the scope in their generated filename, so derive +# the path from npm's machine-readable output instead of duplicating that convention. +PACK_JSON=$(npm pack --json) +TARBALL=$(printf '%s' "$PACK_JSON" | node -e ' +let input = ""; +process.stdin.setEncoding("utf8"); +process.stdin.on("data", (chunk) => (input += chunk)); +process.stdin.on("end", () => { + const filename = JSON.parse(input)[0]?.filename; + if (!filename) process.exit(1); + process.stdout.write(filename); +}); +') + +if [[ ! -f "$TARBALL" ]]; then + echo "npm pack did not create the reported tarball: $TARBALL" >&2 + exit 1 +fi + +printf '%s/%s\n' "$ROOT_DIR" "$TARBALL" diff --git a/scripts/set-package-version.js b/scripts/set-package-version.js index 4dfd32032c2..80695903924 100644 --- a/scripts/set-package-version.js +++ b/scripts/set-package-version.js @@ -22,7 +22,7 @@ packageJson.version = version; const legacyCompatPackageJsonPath = "packages/mux-compat/package.json"; const legacyCompatPackageJson = JSON.parse(fs.readFileSync(legacyCompatPackageJsonPath, "utf8")); legacyCompatPackageJson.version = version; -legacyCompatPackageJson.dependencies.shux = version; +legacyCompatPackageJson.dependencies = { [packageJson.name]: version }; // When version includes a prerelease suffix like "-nightly.N", tell // electron-builder to generate channel-specific manifests (e.g. nightly.yml, diff --git a/scripts/smoke-test-mux-compat.sh b/scripts/smoke-test-mux-compat.sh new file mode 100755 index 00000000000..23b3c4981bc --- /dev/null +++ b/scripts/smoke-test-mux-compat.sh @@ -0,0 +1,53 @@ +#!/usr/bin/env bash +# Smoke test the published `mux` forwarding package against the canonical tarball. + +set -euo pipefail + +CANONICAL_TARBALL="${CANONICAL_TARBALL:-}" +MUX_COMPAT_DIR="${MUX_COMPAT_DIR:-packages/mux-compat}" + +if [[ -z "$CANONICAL_TARBALL" ]] || [[ ! -f "$CANONICAL_TARBALL" ]]; then + echo "CANONICAL_TARBALL must point to the packed @coder/shux tarball" >&2 + exit 1 +fi + +CANONICAL_TARBALL=$(realpath "$CANONICAL_TARBALL") +MUX_COMPAT_DIR=$(realpath "$MUX_COMPAT_DIR") +TEST_DIR=$(mktemp -d) +trap 'rm -rf "$TEST_DIR"' EXIT + +# npm cannot resolve the unpublished scoped dependency, so pack a temporary mux +# package that points at the exact canonical tarball produced by this checkout. +TEMP_MUX_DIR="$TEST_DIR/mux-package" +cp -R "$MUX_COMPAT_DIR" "$TEMP_MUX_DIR" +node - "$TEMP_MUX_DIR/package.json" "$CANONICAL_TARBALL" <<'NODE' +const fs = require("node:fs"); +const [packageJsonPath, canonicalTarball] = process.argv.slice(2); +const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8")); +packageJson.dependencies["@coder/shux"] = `file:${canonicalTarball}`; +fs.writeFileSync(packageJsonPath, `${JSON.stringify(packageJson, null, 2)}\n`); +NODE + +MUX_TARBALL=$(cd "$TEMP_MUX_DIR" && npm pack --json | node -e ' +let input = ""; +process.stdin.setEncoding("utf8"); +process.stdin.on("data", (chunk) => (input += chunk)); +process.stdin.on("end", () => { + const filename = JSON.parse(input)[0]?.filename; + if (!filename) process.exit(1); + process.stdout.write(filename); +}); +') +MUX_TARBALL="$TEMP_MUX_DIR/$MUX_TARBALL" + +INSTALL_DIR="$TEST_DIR/install" +mkdir -p "$INSTALL_DIR" +printf '{"name":"mux-compat-smoke","private":true}\n' >"$INSTALL_DIR/package.json" +(cd "$INSTALL_DIR" && npm install --ignore-scripts --no-audit --no-fund "$MUX_TARBALL") + +if [[ ! -x "$INSTALL_DIR/node_modules/.bin/mux" ]]; then + echo "mux forwarding binary was not installed" >&2 + exit 1 +fi + +"$INSTALL_DIR/node_modules/.bin/mux" --help >/dev/null diff --git a/scripts/smoke-test.sh b/scripts/smoke-test.sh index 7a31f1ca536..0285db76449 100755 --- a/scripts/smoke-test.sh +++ b/scripts/smoke-test.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# Smoke test for the canonical shux npm package and legacy mux binary alias. +# Smoke test for the canonical @coder/shux npm package and legacy mux binary alias. # Tests that the package can be installed and the server starts correctly. set -euo pipefail @@ -104,7 +104,7 @@ cat >package.json < PackagedAppInfo; -const LOWERCASE_ARTIFACT_TEMPLATE = "${name}-${version}-${arch}.${ext}"; +const LEGACY_MUX_BIN_PATH = fileURLToPath( + new URL("../../../packages/mux-compat/bin/mux.js", import.meta.url) +); +const LOWERCASE_ARTIFACT_TEMPLATE = "shux-${version}-${arch}.${ext}"; function expandArtifactName(arch: string, ext: string): string { - return LOWERCASE_ARTIFACT_TEMPLATE.replaceAll("${name}", packageJson.name) - .replaceAll("${version}", packageJson.version) + return LOWERCASE_ARTIFACT_TEMPLATE.replaceAll("${version}", packageJson.version) .replaceAll("${arch}", arch) .replaceAll("${ext}", ext); } describe("shux package transition contract", () => { test("ships one canonical CLI implementation through both command names", () => { - expect(packageJson.name).toBe("shux"); + expect(packageJson.name).toBe("@coder/shux"); + expect(packageJson.publishConfig.access).toBe("public"); expect(packageJson.bin).toEqual({ shux: "dist/cli/index.js", mux: "dist/cli/index.js", @@ -40,7 +48,7 @@ describe("shux package transition contract", () => { test("retains install identity and the legacy deep-link scheme", () => { expect(packageJson.build.appId).toBe("com.mux.app"); expect(packageJson.build.productName).toBe("Shux"); - expect(packageJson.build.executableName).toBe(packageJson.name); + expect(packageJson.build.executableName).toBe("shux"); expect(packageJson.build.protocols[0]?.schemes).toEqual(["shux", "mux"]); }); @@ -87,20 +95,49 @@ describe("shux package transition contract", () => { expect(packageJson.build.win.artifactName).toBe(LOWERCASE_ARTIFACT_TEMPLATE); const expanded = expandArtifactName("arm64", "dmg"); - expect(expanded.startsWith(`${packageJson.name}-`)).toBe(true); - expect(expanded).toBe(`${packageJson.name}-${packageJson.version}-arm64.dmg`); + expect(expanded).toBe(`shux-${packageJson.version}-arm64.dmg`); + expect(expanded.startsWith(`${packageJson.name}-`)).toBe(false); expect(expanded.startsWith(`${packageJson.build.productName}-`)).toBe(false); }); test("keeps the Linux desktop name visible while WM class follows the slug", () => { - expect(packageJson.build.linux.desktop?.StartupWMClass).toBe(packageJson.name); + expect(packageJson.build.linux.desktop?.StartupWMClass).toBe(packageJson.build.executableName); expect(packageJson.build.linux.desktop).not.toHaveProperty("Name"); }); - test("keeps the published mux forwarding package version-locked to shux", () => { + test("keeps the published mux forwarding package version-locked to @coder/shux", () => { expect(legacyPackageJson.name).toBe("mux"); expect(legacyPackageJson.version).toBe(packageJson.version); - expect(legacyPackageJson.dependencies.shux).toBe(packageJson.version); + expect(legacyPackageJson.dependencies).toEqual({ + "@coder/shux": packageJson.version, + }); + }); + + test("executes the legacy mux package through the scoped canonical dependency", () => { + const tempDir = mkdtempSync(path.join(tmpdir(), "shux-mux-compat-")); + const canonicalCliDir = path.join(tempDir, "node_modules", "@coder", "shux", "dist", "cli"); + + try { + mkdirSync(canonicalCliDir, { recursive: true }); + writeFileSync( + path.join(canonicalCliDir, "index.js"), + 'process.stdout.write("forwarded-to-@coder/shux");\n' + ); + + const result = spawnSync("node", [LEGACY_MUX_BIN_PATH], { + encoding: "utf8", + env: { + ...process.env, + NODE_PATH: path.join(tempDir, "node_modules"), + }, + }); + + expect(result.status).toBe(0); + expect(result.stderr).toBe(""); + expect(result.stdout).toBe("forwarded-to-@coder/shux"); + } finally { + rmSync(tempDir, { recursive: true, force: true }); + } }); test("keeps the VS Code Marketplace identity on mux while showing Shux", () => { diff --git a/src/node/services/agentSkills/builtInSkillContent.generated.ts b/src/node/services/agentSkills/builtInSkillContent.generated.ts index 2a16f767a8c..8a19e6229d8 100644 --- a/src/node/services/agentSkills/builtInSkillContent.generated.ts +++ b/src/node/services/agentSkills/builtInSkillContent.generated.ts @@ -4757,7 +4757,7 @@ export const BUILTIN_SKILL_FILES: Record> = { " env:", " ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}", " GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}", - ' run: bunx shux run "Review this PR for critical issues. If any are found, exit with 1 to block merge."', + ' run: bunx @coder/shux run "Review this PR for critical issues. If any are found, exit with 1 to block merge."', "```", "", "`shux run` supports agent-controlled exit codes, so the workflow step can fail when issues are found.", @@ -4853,7 +4853,7 @@ export const BUILTIN_SKILL_FILES: Record> = { " ANTHROPIC_API_KEY: ${{ secrets.AUTO_CLEANUP_ANTHROPIC_API_KEY }}", " GH_TOKEN: ${{ steps.app-token.outputs.token }}", " run: |", - " bunx shux@next run \\", + " bunx @coder/shux@next run \\", " --model anthropic:claude-opus-5 \\", " --thinking xhigh \\", " < .github/prompts/auto-cleanup.md", @@ -6080,16 +6080,16 @@ export const BUILTIN_SKILL_FILES: Record> = { "", "```bash", "# Run agent tasks", - 'npx shux run "Fix the failing tests"', + 'npx @coder/shux run "Fix the failing tests"', "", "# Start the server for remote/mobile access", - "npx shux server --port 3000", + "npx @coder/shux server --port 3000", "```", "", "Or install globally:", "", "```bash", - "npm install -g shux", + "npm install -g @coder/shux", "```", "", "The legacy `mux` package and command forward to the matching Shux release during the transition. See [Mux compatibility](/reference/mux-compatibility) for storage, environment-variable, and downgrade details.", @@ -6501,14 +6501,14 @@ export const BUILTIN_SKILL_FILES: Record> = { "", "```bash", "# Run without installing", - 'npx shux run "Fix the failing tests"', + 'npx @coder/shux run "Fix the failing tests"', "", "# Or install globally", - "npm install -g shux", + "npm install -g @coder/shux", 'shux run "Fix the failing tests"', "```", "", - "Using `npx shux` is especially convenient for CI/CD pipelines where you don't want to manage a global installation.", + "Using `npx @coder/shux` is especially convenient for CI/CD pipelines where you don't want to manage a global installation.", "", "## `shux run`", "", @@ -6516,7 +6516,7 @@ export const BUILTIN_SKILL_FILES: Record> = { "", "```bash", "# Basic usage - run in current directory", - 'npx shux run "Fix the failing tests"', + 'npx @coder/shux run "Fix the failing tests"', "", "# Specify a directory", 'shux run --dir /path/to/project "Add authentication"', @@ -6820,7 +6820,7 @@ export const BUILTIN_SKILL_FILES: Record> = { "", "| Surface | Canonical | Compatibility alias |", "| --------------------- | ---------------------------------- | --------------------------------------------------------- |", - "| npm package | `shux` | `mux` forwarding package |", + "| npm package | `@coder/shux` | `mux` forwarding package |", "| CLI | `shux` | `mux` |", "| Local data | `~/.shux` | `~/.mux` and older `~/.cmux` links |", "| Development data | `~/.shux-dev` | `~/.mux-dev` link |", From 53b3a2c6f9f64ec94eda3b6ee5f2601270e04212 Mon Sep 17 00:00:00 2001 From: Ammar Date: Thu, 20 Aug 2026 11:47:57 -0500 Subject: [PATCH 2/2] fix: use scoped package in ACP docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update the no-install editor configuration and regenerated built-in documentation to invoke @coder/shux. --- _Generated with `mux` • Model: `openai:gpt-5.6-sol` • Thinking: `xhigh` • Cost: `$14.36`_ --- docs/integrations/acp.mdx | 2 +- src/node/services/agentSkills/builtInSkillContent.generated.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/integrations/acp.mdx b/docs/integrations/acp.mdx index dc18c02ffc2..fc876d0416e 100644 --- a/docs/integrations/acp.mdx +++ b/docs/integrations/acp.mdx @@ -39,7 +39,7 @@ Open **Settings** (`Cmd+,`) and add: "Shux": { "type": "custom", "command": "npx", - "args": ["-y", "shux", "acp"] + "args": ["-y", "@coder/shux", "acp"] } } } diff --git a/src/node/services/agentSkills/builtInSkillContent.generated.ts b/src/node/services/agentSkills/builtInSkillContent.generated.ts index 8a19e6229d8..320c0f270d6 100644 --- a/src/node/services/agentSkills/builtInSkillContent.generated.ts +++ b/src/node/services/agentSkills/builtInSkillContent.generated.ts @@ -6139,7 +6139,7 @@ export const BUILTIN_SKILL_FILES: Record> = { ' "Shux": {', ' "type": "custom",', ' "command": "npx",', - ' "args": ["-y", "shux", "acp"]', + ' "args": ["-y", "@coder/shux", "acp"]', " }", " }", "}",