diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c3762c0e9161..97c56043cadd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -34,7 +34,6 @@ jobs: outputs: macos: ${{ steps.detect.outputs.macos }} web: ${{ steps.detect.outputs.web }} - go: ${{ steps.detect.outputs.go }} agent_session_web: ${{ steps.detect.outputs.agent_session_web }} steps: - name: Checkout @@ -55,7 +54,6 @@ jobs: { echo "macos=true" echo "web=true" - echo "go=true" echo "agent_session_web=true" } >> "$GITHUB_OUTPUT" } @@ -110,7 +108,6 @@ jobs: { echo "macos=false" echo "web=false" - echo "go=false" echo "agent_session_web=false" } >> "$GITHUB_OUTPUT" exit 0 @@ -325,9 +322,6 @@ jobs: - name: Validate CI change area filter run: python3 tests/test_ci_change_areas.py - - name: Validate release attestation retry guard - run: ./tests/test_ci_attestation_retry.sh - - name: Validate Python R2 appcast upload guard run: ./tests/test_ci_r2_upload_python.sh @@ -423,27 +417,6 @@ jobs: GHOSTTYKIT_DOWNLOAD_RETRY_DELAY: "1" run: ./scripts/download-prebuilt-ghosttykit.sh --verify-only - remote-daemon-tests: - needs: changes - if: ${{ needs.changes.outputs.go == 'true' }} - runs-on: ${{ vars.LINUX_RUNNER || 'blacksmith-4vcpu-ubuntu-2404' }} - steps: - - name: Checkout - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - - name: Setup Go - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 - with: - go-version-file: daemon/remote/go.mod - cache-dependency-path: daemon/remote/go.sum - - - name: Run remote daemon tests - working-directory: daemon/remote - run: go test ./... - - - name: Validate remote daemon release assets - run: ./tests/test_remote_daemon_release_assets.sh - web-typecheck: needs: changes if: ${{ needs.changes.outputs.web == 'true' }} @@ -1820,7 +1793,6 @@ jobs: - changes - workflow-guard-tests - ghosttykit-release-check - - remote-daemon-tests - web-typecheck - react-apps-check - diff-sidecar-check @@ -1842,7 +1814,6 @@ jobs: needs = json.loads(os.environ["PREFLIGHT_NEEDS"]) required = ("changes", "workflow-guard-tests", "ghosttykit-release-check") allowed_routed = { - "remote-daemon-tests", "web-typecheck", "react-apps-check", "diff-sidecar-check", @@ -1858,7 +1829,6 @@ jobs: outputs = needs["changes"].get("outputs", {}) routed_outputs = { - "remote-daemon-tests": "go", "web-typecheck": "web", "react-apps-check": "web", "diff-sidecar-check": "macos", @@ -1883,7 +1853,6 @@ jobs: "routes: " f"macos={outputs.get('macos')} " f"web={outputs.get('web')} " - f"go={outputs.get('go')} " f"agent_session_web={outputs.get('agent_session_web')}" ) for name, data in sorted(needs.items()): @@ -2414,7 +2383,6 @@ jobs: - changes - workflow-guard-tests - ghosttykit-release-check - - remote-daemon-tests - web-typecheck - react-apps-check - diff-sidecar-check diff --git a/.github/workflows/cloud-vm-env-audit.yml b/.github/workflows/cloud-vm-env-audit.yml index f1481c86880d..d05b8c325efc 100644 --- a/.github/workflows/cloud-vm-env-audit.yml +++ b/.github/workflows/cloud-vm-env-audit.yml @@ -1,8 +1,8 @@ name: Cloud VM env audit # Guards against deployed-env / code drift: the 2026-08-26 outage shipped code -# that assumed CMUX_VM_DEFAULT_PROVIDER=blaxel while production still said -# freestyle, and every Cloud VM create 503ed for two days with nothing paging. +# that assumed one CMUX_VM_DEFAULT_PROVIDER while production still said +# another, and every Cloud VM create 503ed for two days with nothing paging. # This audit pulls the real production env and fails when the default # provider's image value is missing from the image manifest, so drift is a red # workflow on merge (and daily) instead of a user-facing outage. diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 3d8201e17572..8949695878be 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -381,7 +381,7 @@ jobs: if: needs.decide.outputs.should_build == 'true' && (github.event_name != 'schedule' || github.event.schedule == '47 8 * * *') # Sign and notarize on the same macOS 26 lane proven by stable releases. runs-on: ${{ vars.MACOS_RUNNER_26 || 'blacksmith-6vcpu-macos-26' }} - # Start the standalone helper submission before remote-daemon preparation so + # Start the standalone helper submission early so # Apple's first wait overlaps useful work; finish it before the final DMG. timeout-minutes: 60 env: @@ -457,12 +457,6 @@ jobs: chmod +x "$wrapper_dir/create-dmg" echo "$wrapper_dir" >> "$GITHUB_PATH" - - name: Setup Go - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 - with: - go-version-file: daemon/remote/go.mod - cache-dependency-path: daemon/remote/go.sum - - name: Derive Sparkle public key from private key env: SPARKLE_PRIVATE_KEY: ${{ secrets.SPARKLE_PRIVATE_KEY }} @@ -547,7 +541,6 @@ jobs: { echo "NIGHTLY_BUILD=${NIGHTLY_BUILD}" echo "NIGHTLY_MARKETING_VERSION=${NIGHTLY_MARKETING_VERSION}" - echo "NIGHTLY_REMOTE_DAEMON_VERSION=${NIGHTLY_MARKETING_VERSION}" echo "NIGHTLY_DMG_IMMUTABLE=${NIGHTLY_DMG_IMMUTABLE}" } >> "$GITHUB_ENV" @@ -629,52 +622,6 @@ jobs: cmux.nightly.entitlements \ "$APPLE_SIGNING_IDENTITY" - - name: Build remote daemon nightly assets and inject manifest - run: | - set -euo pipefail - # Build with --asset-suffix so manifest download URLs point to - # immutable, build-specific asset names (e.g. cmuxd-remote-darwin-arm64-2362248028801). - # This prevents checksum mismatches when a newer nightly overwrites - # the shared "latest" assets on the release. - ./scripts/build_remote_daemon_release_assets.sh \ - --version "$NIGHTLY_REMOTE_DAEMON_VERSION" \ - --release-tag "nightly" \ - --repo "manaflow-ai/cmux" \ - --output-dir "remote-daemon-assets" \ - --asset-suffix "$NIGHTLY_BUILD" - MANIFEST_JSON="$(python3 -c 'import json,sys; print(json.dumps(json.load(open(sys.argv[1], encoding="utf-8")), separators=(",",":")))' "remote-daemon-assets/cmuxd-remote-manifest-${NIGHTLY_BUILD}.json")" - APP_PLIST="build-universal/Build/Products/Release/cmux NIGHTLY.app/Contents/Info.plist" - if [ ! -f "$APP_PLIST" ]; then - echo "Missing nightly app Info.plist at $APP_PLIST" >&2 - exit 1 - fi - plutil -remove CMUXRemoteDaemonManifestJSON "$APP_PLIST" >/dev/null 2>&1 || true - plutil -insert CMUXRemoteDaemonManifestJSON -string "$MANIFEST_JSON" "$APP_PLIST" - # Also create unsuffixed "latest" copies for the release page and - # any tooling that fetches the generic asset names. The manifest's - # downloadURLs still point to the versioned filenames (intentional: - # the live manifest is used by the client-side checksum fallback - # which only reads sha256, not downloadURL). The unsuffixed copies - # are convenience aliases and don't carry build-provenance - # attestation (attested versioned files are canonical). - for platform in darwin-arm64 darwin-amd64 linux-arm64 linux-amd64; do - cp "remote-daemon-assets/cmuxd-remote-${platform}-${NIGHTLY_BUILD}" \ - "remote-daemon-assets/cmuxd-remote-${platform}" - done - # Regenerate unsuffixed checksums with generic filenames so - # `shasum -c cmuxd-remote-checksums.txt` works against the aliases. - ( - cd remote-daemon-assets - shasum -a 256 \ - cmuxd-remote-darwin-arm64 \ - cmuxd-remote-darwin-amd64 \ - cmuxd-remote-linux-arm64 \ - cmuxd-remote-linux-amd64 \ - > cmuxd-remote-checksums.txt - ) - cp "remote-daemon-assets/cmuxd-remote-manifest-${NIGHTLY_BUILD}.json" \ - "remote-daemon-assets/cmuxd-remote-manifest.json" - - name: Embed nightly provisioning profile env: APPLE_NIGHTLY_PROVISIONING_PROFILE_BASE64: ${{ secrets.APPLE_NIGHTLY_PROVISIONING_PROFILE_BASE64 }} @@ -757,31 +704,6 @@ jobs: # installs to migrate onto the unified nightly appcast. cp appcast.xml appcast-universal.xml - - name: Attest remote daemon nightly assets - id: attest-remote-daemon-nightly-assets - continue-on-error: true - uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v4.1.0 - with: - subject-path: | - remote-daemon-assets/cmuxd-remote-darwin-arm64-${{ env.NIGHTLY_BUILD }} - remote-daemon-assets/cmuxd-remote-darwin-amd64-${{ env.NIGHTLY_BUILD }} - remote-daemon-assets/cmuxd-remote-linux-arm64-${{ env.NIGHTLY_BUILD }} - remote-daemon-assets/cmuxd-remote-linux-amd64-${{ env.NIGHTLY_BUILD }} - remote-daemon-assets/cmuxd-remote-checksums-${{ env.NIGHTLY_BUILD }}.txt - remote-daemon-assets/cmuxd-remote-manifest-${{ env.NIGHTLY_BUILD }}.json - - - name: Retry remote daemon nightly asset attestation - if: steps.attest-remote-daemon-nightly-assets.outcome == 'failure' - uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v4.1.0 - with: - subject-path: | - remote-daemon-assets/cmuxd-remote-darwin-arm64-${{ env.NIGHTLY_BUILD }} - remote-daemon-assets/cmuxd-remote-darwin-amd64-${{ env.NIGHTLY_BUILD }} - remote-daemon-assets/cmuxd-remote-linux-arm64-${{ env.NIGHTLY_BUILD }} - remote-daemon-assets/cmuxd-remote-linux-amd64-${{ env.NIGHTLY_BUILD }} - remote-daemon-assets/cmuxd-remote-checksums-${{ env.NIGHTLY_BUILD }}.txt - remote-daemon-assets/cmuxd-remote-manifest-${{ env.NIGHTLY_BUILD }}.json - - name: Upload branch nightly artifacts if: needs.decide.outputs.should_publish != 'true' uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 @@ -790,7 +712,6 @@ jobs: path: | cmux-nightly-macos*.dmg appcast.xml - remote-daemon-assets/cmuxd-remote-* appcast-universal.xml if-no-files-found: error @@ -827,7 +748,6 @@ jobs: cmux-nightly-macos-${{ github.run_id }}*.dmg cmux-nightly-macos.dmg appcast.xml - remote-daemon-assets/cmuxd-remote-* appcast-universal.xml overwrite_files: true diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d070936a3355..68eabaa00e3f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -227,13 +227,6 @@ jobs: if: steps.guard_release_assets.outputs.skip_all != 'true' run: python3 scripts/ci/sanitize-xcode-source-packages-cache.py .spm-cache - - name: Setup Go - if: steps.guard_release_assets.outputs.skip_all != 'true' - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 - with: - go-version-file: daemon/remote/go.mod - cache-dependency-path: daemon/remote/go.sum - - name: Derive Sparkle public key from private key if: steps.guard_release_assets.outputs.skip_all != 'true' env: @@ -336,21 +329,6 @@ jobs: ./scripts/verify-diff-sidecar-artifact.sh "$DIFF_SIDECAR" [[ "$SDK_VERSION" == 26.* ]] - - name: Build remote daemon release assets and inject manifest - if: steps.guard_release_assets.outputs.skip_all != 'true' - run: | - set -euo pipefail - APP_PLIST="build-universal/Build/Products/Release/cmux.app/Contents/Info.plist" - APP_VERSION=$(/usr/libexec/PlistBuddy -c "Print :CFBundleShortVersionString" "$APP_PLIST") - ./scripts/build_remote_daemon_release_assets.sh \ - --version "$APP_VERSION" \ - --release-tag "$GITHUB_REF_NAME" \ - --repo "manaflow-ai/cmux" \ - --output-dir "remote-daemon-assets" - MANIFEST_JSON="$(python3 -c 'import json,sys; print(json.dumps(json.load(open(sys.argv[1], encoding="utf-8")), separators=(",",":")))' remote-daemon-assets/cmuxd-remote-manifest.json)" - plutil -remove CMUXRemoteDaemonManifestJSON "$APP_PLIST" >/dev/null 2>&1 || true - plutil -insert CMUXRemoteDaemonManifestJSON -string "$MANIFEST_JSON" "$APP_PLIST" - - name: Run CLI version memory guard regression if: steps.guard_release_assets.outputs.skip_all != 'true' run: | @@ -516,32 +494,6 @@ jobs: fi ./scripts/sparkle_generate_appcast.sh cmux-macos.dmg "$GITHUB_REF_NAME" appcast.xml - - name: Attest remote daemon release assets - id: attest-remote-daemon-release-assets - if: steps.guard_release_assets.outputs.skip_all != 'true' - continue-on-error: true - uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v4.1.0 - with: - subject-path: | - remote-daemon-assets/cmuxd-remote-darwin-arm64 - remote-daemon-assets/cmuxd-remote-darwin-amd64 - remote-daemon-assets/cmuxd-remote-linux-arm64 - remote-daemon-assets/cmuxd-remote-linux-amd64 - remote-daemon-assets/cmuxd-remote-checksums.txt - remote-daemon-assets/cmuxd-remote-manifest.json - - - name: Retry remote daemon release asset attestation - if: steps.guard_release_assets.outputs.skip_all != 'true' && steps.attest-remote-daemon-release-assets.outcome == 'failure' - uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v4.1.0 - with: - subject-path: | - remote-daemon-assets/cmuxd-remote-darwin-arm64 - remote-daemon-assets/cmuxd-remote-darwin-amd64 - remote-daemon-assets/cmuxd-remote-linux-arm64 - remote-daemon-assets/cmuxd-remote-linux-amd64 - remote-daemon-assets/cmuxd-remote-checksums.txt - remote-daemon-assets/cmuxd-remote-manifest.json - - name: Upload build artifacts (dry-run) if: steps.guard_release_assets.outputs.skip_upload != 'true' && github.event_name == 'workflow_dispatch' uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 @@ -550,7 +502,6 @@ jobs: path: | cmux-macos.dmg appcast.xml - remote-daemon-assets/cmuxd-remote-* if-no-files-found: error - name: Upload release asset @@ -560,12 +511,6 @@ jobs: files: | cmux-macos.dmg appcast.xml - remote-daemon-assets/cmuxd-remote-darwin-arm64 - remote-daemon-assets/cmuxd-remote-darwin-amd64 - remote-daemon-assets/cmuxd-remote-linux-arm64 - remote-daemon-assets/cmuxd-remote-linux-amd64 - remote-daemon-assets/cmuxd-remote-checksums.txt - remote-daemon-assets/cmuxd-remote-manifest.json generate_release_notes: true overwrite_files: false diff --git a/.github/workflows/tmux-corpus.yml b/.github/workflows/tmux-corpus.yml index 2516b8c12605..321b55ebb493 100644 --- a/.github/workflows/tmux-corpus.yml +++ b/.github/workflows/tmux-corpus.yml @@ -1,13 +1,8 @@ -name: tmux corpus +name: terminal nightly on: # Temporarily manual-only beginning 2026-07-13 to pause automatic CI. workflow_dispatch: - inputs: - fuzztime: - description: Time per Go fuzz target - required: false - default: 2m permissions: actions: write @@ -18,42 +13,6 @@ concurrency: cancel-in-progress: false jobs: - remote-daemon-fuzz: - runs-on: ${{ vars.LINUX_RUNNER || 'blacksmith-4vcpu-ubuntu-2404' }} - timeout-minutes: 30 - steps: - - name: Checkout - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - persist-credentials: false - - - name: Setup Go - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 - with: - go-version-file: daemon/remote/go.mod - cache-dependency-path: daemon/remote/go.sum - - - name: Run deterministic tmux corpus tests - working-directory: daemon/remote - run: go test ./... - - - name: Run tmux corpus fuzz targets - working-directory: daemon/remote - env: - FUZZTIME: ${{ github.event_name == 'pull_request' && '30s' || github.event.inputs.fuzztime || '2m' }} - run: | - set -euo pipefail - for target in \ - FuzzTmuxCompatArgParser \ - FuzzTmuxRenderFormatSupportedSubset \ - FuzzTmuxSendKeysTokens \ - FuzzConsumeWebSocketLease \ - FuzzNormalizePTYSize \ - FuzzWebSocketPTYControlFrame - do - go test ./cmd/cmuxd-remote -run '^$' -fuzz "^${target}$" -fuzztime "$FUZZTIME" - done - terminal-nightly: if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' runs-on: ${{ vars.MACOS_RUNNER_15 || 'blacksmith-6vcpu-macos-15' }} diff --git a/CLI/cmux.swift b/CLI/cmux.swift index 74756a50769c..fe78bb8c0057 100644 --- a/CLI/cmux.swift +++ b/CLI/cmux.swift @@ -4294,7 +4294,7 @@ struct CMUXCLI { // never pins an image id unless the person passes `--image`: a pinned id // that drifted from the web deploy's manifest failed every create with // `vm_image_config_error`. - /// `--size` spellings → memory in MB. vCPUs scale with memory on Blaxel. + /// `--size` spellings → memory in MB. vCPUs scale with memory. private static let cloudVMSizeAliases: [String: Int] = [ "2g": 2048, "2gb": 2048, "small": 2048, "4g": 4096, "4gb": 4096, "medium": 4096, @@ -4597,7 +4597,7 @@ struct CMUXCLI { return nil } let normalized = trimmed.lowercased() - guard normalized == "e2b" || normalized == "freestyle" || normalized == "daytona" || normalized == "blaxel" else { + guard normalized == "e2b" || normalized == "freestyle" || normalized == "daytona" else { throw CLIError(message: """ vm new: unsupported Cloud VM service override. @@ -5861,11 +5861,15 @@ struct CMUXCLI { let (nameOpt, rem1b) = parseOption(rem1a, name: "--name") let (windowOpt, rem2) = parseOption(rem1b, name: "--window") let detach = hasFlag(rem2, name: "--detach") || hasFlag(rem2, name: "-d") - // A machine comes with its screen: new machines boot the desktop image - // (xfce + noVNC) unless the person asks for a shell-only box with --base. - // --desktop stays accepted for scripts written against the old default. - let base = hasFlag(rem2, name: "--base") || hasFlag(rem2, name: "--no-desktop") - let desktop = !base + // No provider ships a desktop image right now, so a bare `vm new` + // asks for a shell-only machine; requesting `--desktop` anyway fails + // closed with a server-side image config error rather than silently + // handing back a screenless box. Flip this back to desktop-by-default + // once a desktop image lands in the manifest. + // `--base`/`--no-desktop` stay accepted for scripts written against + // the old desktop default. + _ = hasFlag(rem2, name: "--base") || hasFlag(rem2, name: "--no-desktop") + let desktop = hasFlag(rem2, name: "--desktop") let (sizeOpt, rem3) = parseOption(rem2, name: "--size") let memoryMb: Int? if let sizeOpt { @@ -5891,8 +5895,8 @@ struct CMUXCLI { vm new: unknown flag '\(unknown)'. Known flags: - --base shell-only machine (no desktop) - --desktop machine with a screen (default) + --base shell-only machine (no desktop, the default) + --desktop machine with a screen (no image available yet) --size <2g|4g|8g|16g|24g|32g> --name