diff --git a/.github/workflows/nix.yml b/.github/workflows/nix.yml index 1897fa4a18..1eca8ed463 100644 --- a/.github/workflows/nix.yml +++ b/.github/workflows/nix.yml @@ -8,7 +8,7 @@ concurrency: jobs: required: name: "Required Checks: Nix" - runs-on: namespace-profile-ghostty-sm + runs-on: ubuntu-24.04 needs: - check-zig-cache-hash steps: @@ -32,20 +32,13 @@ jobs: exit 1 check-zig-cache-hash: - if: github.repository == 'ghostty-org/ghostty' - runs-on: namespace-profile-ghostty-sm + runs-on: ubuntu-24.04 env: - ZIG_LOCAL_CACHE_DIR: /zig/local-cache - ZIG_GLOBAL_CACHE_DIR: /zig/global-cache + ZIG_LOCAL_CACHE_DIR: ${{ github.workspace }}/.zig-cache/local + ZIG_GLOBAL_CACHE_DIR: ${{ github.workspace }}/.zig-cache/global steps: - name: Checkout code uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - name: Setup Cache - uses: namespacelabs/nscloud-cache-action@a90bb5d4b27522ce881c6e98eebd7d7e6d1653f9 # v1.4.2 - with: - path: | - /nix - /zig - name: Setup Nix uses: cachix/install-nix-action@2126ae7fc54c9df00dd18f7f18754393182c73cd # v31.9.1 with: diff --git a/.github/workflows/sync-upstream.yml b/.github/workflows/sync-upstream.yml index ad95281513..0af29fccba 100644 --- a/.github/workflows/sync-upstream.yml +++ b/.github/workflows/sync-upstream.yml @@ -3,7 +3,7 @@ name: Sync with Upstream on: schedule: # Run daily at 6am UTC - - cron: '0 6 * * *' + - cron: "0 6 * * *" workflow_dispatch: # Allow manual trigger @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 0 token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4d7b1292b2..c7e9f86e57 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -12,8 +12,7 @@ concurrency: jobs: paths: - if: github.repository == 'ghostty-org/ghostty' - runs-on: namespace-profile-ghostty-xsm + runs-on: ubuntu-24.04 outputs: macos: ${{ steps.filter.outputs.macos }} steps: @@ -27,7 +26,7 @@ jobs: required: name: "Required Checks: Test" - runs-on: namespace-profile-ghostty-xsm + runs-on: ubuntu-24.04 needs: - paths - build-bench @@ -84,22 +83,15 @@ jobs: build-bench: # We build benchmarks on large because it uses ReleaseFast - runs-on: namespace-profile-ghostty-lg + runs-on: ubuntu-24.04 needs: test env: - ZIG_LOCAL_CACHE_DIR: /zig/local-cache - ZIG_GLOBAL_CACHE_DIR: /zig/global-cache + ZIG_LOCAL_CACHE_DIR: ${{ github.workspace }}/.zig-cache/local + ZIG_GLOBAL_CACHE_DIR: ${{ github.workspace }}/.zig-cache/global steps: - name: Checkout code uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - name: Setup Cache - uses: namespacelabs/nscloud-cache-action@a90bb5d4b27522ce881c6e98eebd7d7e6d1653f9 # v1.4.2 - with: - path: | - /nix - /zig - # Install Nix and use that to run our tests so our environment matches exactly. - uses: cachix/install-nix-action@2126ae7fc54c9df00dd18f7f18754393182c73cd # v31.9.1 with: @@ -127,22 +119,15 @@ jobs: zig-vt-stream, ] name: Example ${{ matrix.dir }} - runs-on: namespace-profile-ghostty-sm + runs-on: ubuntu-24.04 needs: test env: - ZIG_LOCAL_CACHE_DIR: /zig/local-cache - ZIG_GLOBAL_CACHE_DIR: /zig/global-cache + ZIG_LOCAL_CACHE_DIR: ${{ github.workspace }}/.zig-cache/local + ZIG_GLOBAL_CACHE_DIR: ${{ github.workspace }}/.zig-cache/global steps: - name: Checkout code uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - name: Setup Cache - uses: namespacelabs/nscloud-cache-action@a90bb5d4b27522ce881c6e98eebd7d7e6d1653f9 # v1.4.2 - with: - path: | - /nix - /zig - # Install Nix and use that to run our tests so our environment matches exactly. - uses: cachix/install-nix-action@2126ae7fc54c9df00dd18f7f18754393182c73cd # v31.9.1 with: @@ -160,22 +145,15 @@ jobs: build-flatpak: strategy: fail-fast: false - runs-on: namespace-profile-ghostty-sm + runs-on: ubuntu-24.04 needs: test env: - ZIG_LOCAL_CACHE_DIR: /zig/local-cache - ZIG_GLOBAL_CACHE_DIR: /zig/global-cache + ZIG_LOCAL_CACHE_DIR: ${{ github.workspace }}/.zig-cache/local + ZIG_GLOBAL_CACHE_DIR: ${{ github.workspace }}/.zig-cache/global steps: - name: Checkout code uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - name: Setup Cache - uses: namespacelabs/nscloud-cache-action@a90bb5d4b27522ce881c6e98eebd7d7e6d1653f9 # v1.4.2 - with: - path: | - /nix - /zig - # Install Nix and use that to run our tests so our environment matches exactly. - uses: cachix/install-nix-action@2126ae7fc54c9df00dd18f7f18754393182c73cd # v31.9.1 with: @@ -194,22 +172,15 @@ jobs: build-snap: strategy: fail-fast: false - runs-on: namespace-profile-ghostty-sm + runs-on: ubuntu-24.04 needs: test env: - ZIG_LOCAL_CACHE_DIR: /zig/local-cache - ZIG_GLOBAL_CACHE_DIR: /zig/global-cache + ZIG_LOCAL_CACHE_DIR: ${{ github.workspace }}/.zig-cache/local + ZIG_GLOBAL_CACHE_DIR: ${{ github.workspace }}/.zig-cache/global steps: - name: Checkout code uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - name: Setup Cache - uses: namespacelabs/nscloud-cache-action@a90bb5d4b27522ce881c6e98eebd7d7e6d1653f9 # v1.4.2 - with: - path: | - /nix - /zig - # Install Nix and use that to run our tests so our environment matches exactly. - uses: cachix/install-nix-action@2126ae7fc54c9df00dd18f7f18754393182c73cd # v31.9.1 with: @@ -238,22 +209,15 @@ jobs: x86_64-windows, wasm32-freestanding, ] - runs-on: namespace-profile-ghostty-sm + runs-on: ubuntu-24.04 needs: test env: - ZIG_LOCAL_CACHE_DIR: /zig/local-cache - ZIG_GLOBAL_CACHE_DIR: /zig/global-cache + ZIG_LOCAL_CACHE_DIR: ${{ github.workspace }}/.zig-cache/local + ZIG_GLOBAL_CACHE_DIR: ${{ github.workspace }}/.zig-cache/global steps: - name: Checkout code uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - name: Setup Cache - uses: namespacelabs/nscloud-cache-action@a90bb5d4b27522ce881c6e98eebd7d7e6d1653f9 # v1.4.2 - with: - path: | - /nix - /zig - # Install Nix and use that to run our tests so our environment matches exactly. - uses: cachix/install-nix-action@2126ae7fc54c9df00dd18f7f18754393182c73cd # v31.9.1 with: @@ -274,7 +238,7 @@ jobs: strategy: matrix: target: [aarch64-macos, x86_64-macos, aarch64-ios] - runs-on: namespace-profile-ghostty-macos-tahoe + runs-on: macos-latest needs: test steps: - name: Checkout code @@ -301,23 +265,16 @@ jobs: strategy: fail-fast: false matrix: - os: [namespace-profile-ghostty-md, namespace-profile-ghostty-md-arm64] + os: [ubuntu-24.04] runs-on: ${{ matrix.os }} needs: test env: - ZIG_LOCAL_CACHE_DIR: /zig/local-cache - ZIG_GLOBAL_CACHE_DIR: /zig/global-cache + ZIG_LOCAL_CACHE_DIR: ${{ github.workspace }}/.zig-cache/local + ZIG_GLOBAL_CACHE_DIR: ${{ github.workspace }}/.zig-cache/global steps: - name: Checkout code uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - name: Setup Cache - uses: namespacelabs/nscloud-cache-action@a90bb5d4b27522ce881c6e98eebd7d7e6d1653f9 # v1.4.2 - with: - path: | - /nix - /zig - # Install Nix and use that to run our tests so our environment matches exactly. - uses: cachix/install-nix-action@2126ae7fc54c9df00dd18f7f18754393182c73cd # v31.9.1 with: @@ -331,22 +288,15 @@ jobs: run: nix develop -c zig build build-linux-libghostty: - runs-on: namespace-profile-ghostty-md + runs-on: ubuntu-24.04 needs: test env: - ZIG_LOCAL_CACHE_DIR: /zig/local-cache - ZIG_GLOBAL_CACHE_DIR: /zig/global-cache + ZIG_LOCAL_CACHE_DIR: ${{ github.workspace }}/.zig-cache/local + ZIG_GLOBAL_CACHE_DIR: ${{ github.workspace }}/.zig-cache/global steps: - name: Checkout code uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - name: Setup Cache - uses: namespacelabs/nscloud-cache-action@a90bb5d4b27522ce881c6e98eebd7d7e6d1653f9 # v1.4.2 - with: - path: | - /nix - /zig - # Install Nix and use that to run our tests so our environment matches exactly. - uses: cachix/install-nix-action@2126ae7fc54c9df00dd18f7f18754393182c73cd # v31.9.1 with: @@ -363,23 +313,16 @@ jobs: strategy: fail-fast: false matrix: - os: [namespace-profile-ghostty-md, namespace-profile-ghostty-md-arm64] + os: [ubuntu-24.04] runs-on: ${{ matrix.os }} needs: test env: - ZIG_LOCAL_CACHE_DIR: /zig/local-cache - ZIG_GLOBAL_CACHE_DIR: /zig/global-cache + ZIG_LOCAL_CACHE_DIR: ${{ github.workspace }}/.zig-cache/local + ZIG_GLOBAL_CACHE_DIR: ${{ github.workspace }}/.zig-cache/global steps: - name: Checkout code uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - name: Setup Cache - uses: namespacelabs/nscloud-cache-action@a90bb5d4b27522ce881c6e98eebd7d7e6d1653f9 # v1.4.2 - with: - path: | - /nix - /zig - # Install Nix and use that to run our tests so our environment matches exactly. - uses: cachix/install-nix-action@2126ae7fc54c9df00dd18f7f18754393182c73cd # v31.9.1 with: @@ -408,24 +351,17 @@ jobs: run: nm result/bin/.ghostty-wrapped 2>&1 | grep -q 'main_ghostty.main' build-dist: - runs-on: namespace-profile-ghostty-md + runs-on: ubuntu-24.04 needs: test outputs: artifact-id: ${{ steps.upload-artifact.outputs.artifact-id }} env: - ZIG_LOCAL_CACHE_DIR: /zig/local-cache - ZIG_GLOBAL_CACHE_DIR: /zig/global-cache + ZIG_LOCAL_CACHE_DIR: ${{ github.workspace }}/.zig-cache/local + ZIG_GLOBAL_CACHE_DIR: ${{ github.workspace }}/.zig-cache/global steps: - name: Checkout code uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - name: Setup Cache - uses: namespacelabs/nscloud-cache-action@a90bb5d4b27522ce881c6e98eebd7d7e6d1653f9 # v1.4.2 - with: - path: | - /nix - /zig - # Install Nix and use that to run our tests so our environment matches exactly. - uses: cachix/install-nix-action@2126ae7fc54c9df00dd18f7f18754393182c73cd # v31.9.1 with: @@ -451,8 +387,11 @@ jobs: trigger-snap: if: github.event_name != 'pull_request' - runs-on: namespace-profile-ghostty-xsm + runs-on: ubuntu-24.04 needs: [build-dist, build-snap] + permissions: + actions: write + contents: read steps: - name: Checkout code uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 @@ -469,8 +408,11 @@ jobs: trigger-flatpak: if: github.event_name != 'pull_request' - runs-on: namespace-profile-ghostty-xsm + runs-on: ubuntu-24.04 needs: [build-dist, build-flatpak] + permissions: + actions: write + contents: read steps: - name: Checkout code uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 @@ -486,7 +428,7 @@ jobs: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} build-macos: - runs-on: namespace-profile-ghostty-macos-tahoe + runs-on: macos-latest needs: test steps: - name: Checkout code @@ -520,16 +462,17 @@ jobs: # codesigning. IMPORTANT: this must NOT run in a Nix environment. # Nix breaks xcodebuild so this has to be run outside. - name: Build Ghostty.app - run: cd macos && xcodebuild -target Ghostty + run: cd macos && xcodebuild -target Ghostree # Build the iOS target without code signing just to verify it works. - name: Build Ghostty iOS + if: github.repository == 'ghostty-org/ghostty' run: | cd macos xcodebuild -target Ghostty-iOS "CODE_SIGNING_ALLOWED=NO" build-macos-freetype: - runs-on: namespace-profile-ghostty-macos-tahoe + runs-on: macos-latest needs: test steps: - name: Checkout code @@ -632,13 +575,12 @@ jobs: run: Get-Content -Path ".\build.log" test: - if: github.repository == 'ghostty-org/ghostty' - runs-on: namespace-profile-ghostty-md + runs-on: ubuntu-24.04 outputs: zig_version: ${{ steps.zig.outputs.version }} env: - ZIG_LOCAL_CACHE_DIR: /zig/local-cache - ZIG_GLOBAL_CACHE_DIR: /zig/global-cache + ZIG_LOCAL_CACHE_DIR: ${{ github.workspace }}/.zig-cache/local + ZIG_GLOBAL_CACHE_DIR: ${{ github.workspace }}/.zig-cache/global steps: - name: Checkout code uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 @@ -648,13 +590,6 @@ jobs: run: | echo "version=$(sed -n -E 's/^\s*\.?minimum_zig_version\s*=\s*"([^"]+)".*/\1/p' build.zig.zon)" >> $GITHUB_OUTPUT - - name: Setup Cache - uses: namespacelabs/nscloud-cache-action@a90bb5d4b27522ce881c6e98eebd7d7e6d1653f9 # v1.4.2 - with: - path: | - /nix - /zig - # Install Nix and use that to run our tests so our environment matches exactly. - uses: cachix/install-nix-action@2126ae7fc54c9df00dd18f7f18754393182c73cd # v31.9.1 with: @@ -681,22 +616,15 @@ jobs: x11: ["true", "false"] wayland: ["true", "false"] name: GTK x11=${{ matrix.x11 }} wayland=${{ matrix.wayland }} - runs-on: namespace-profile-ghostty-sm + runs-on: ubuntu-24.04 needs: test env: - ZIG_LOCAL_CACHE_DIR: /zig/local-cache - ZIG_GLOBAL_CACHE_DIR: /zig/global-cache + ZIG_LOCAL_CACHE_DIR: ${{ github.workspace }}/.zig-cache/local + ZIG_GLOBAL_CACHE_DIR: ${{ github.workspace }}/.zig-cache/global steps: - name: Checkout code uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - name: Setup Cache - uses: namespacelabs/nscloud-cache-action@a90bb5d4b27522ce881c6e98eebd7d7e6d1653f9 # v1.4.2 - with: - path: | - /nix - /zig - # Install Nix and use that to run our tests so our environment matches exactly. - uses: cachix/install-nix-action@2126ae7fc54c9df00dd18f7f18754393182c73cd # v31.9.1 with: @@ -729,22 +657,15 @@ jobs: matrix: simd: ["true", "false"] name: Build -Dsimd=${{ matrix.simd }} - runs-on: namespace-profile-ghostty-sm + runs-on: ubuntu-24.04 needs: test env: - ZIG_LOCAL_CACHE_DIR: /zig/local-cache - ZIG_GLOBAL_CACHE_DIR: /zig/global-cache + ZIG_LOCAL_CACHE_DIR: ${{ github.workspace }}/.zig-cache/local + ZIG_GLOBAL_CACHE_DIR: ${{ github.workspace }}/.zig-cache/global steps: - name: Checkout code uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - name: Setup Cache - uses: namespacelabs/nscloud-cache-action@a90bb5d4b27522ce881c6e98eebd7d7e6d1653f9 # v1.4.2 - with: - path: | - /nix - /zig - # Install Nix and use that to run our tests so our environment matches exactly. - uses: cachix/install-nix-action@2126ae7fc54c9df00dd18f7f18754393182c73cd # v31.9.1 with: @@ -764,22 +685,15 @@ jobs: matrix: sentry: ["true", "false"] name: Build -Dsentry=${{ matrix.sentry }} - runs-on: namespace-profile-ghostty-sm + runs-on: ubuntu-24.04 needs: test env: - ZIG_LOCAL_CACHE_DIR: /zig/local-cache - ZIG_GLOBAL_CACHE_DIR: /zig/global-cache + ZIG_LOCAL_CACHE_DIR: ${{ github.workspace }}/.zig-cache/local + ZIG_GLOBAL_CACHE_DIR: ${{ github.workspace }}/.zig-cache/global steps: - name: Checkout code uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - name: Setup Cache - uses: namespacelabs/nscloud-cache-action@a90bb5d4b27522ce881c6e98eebd7d7e6d1653f9 # v1.4.2 - with: - path: | - /nix - /zig - # Install Nix and use that to run our tests so our environment matches exactly. - uses: cachix/install-nix-action@2126ae7fc54c9df00dd18f7f18754393182c73cd # v31.9.1 with: @@ -794,7 +708,7 @@ jobs: nix develop -c zig build -Dsentry=${{ matrix.sentry }} test-macos: - runs-on: namespace-profile-ghostty-macos-tahoe + runs-on: macos-latest needs: test steps: - name: Checkout code @@ -827,23 +741,16 @@ jobs: fail-fast: false matrix: i18n: ["true", "false"] - name: Build -Di18n=${{ matrix.simd }} - runs-on: namespace-profile-ghostty-sm + name: Build -Di18n=${{ matrix.i18n }} + runs-on: ubuntu-24.04 needs: test env: - ZIG_LOCAL_CACHE_DIR: /zig/local-cache - ZIG_GLOBAL_CACHE_DIR: /zig/global-cache + ZIG_LOCAL_CACHE_DIR: ${{ github.workspace }}/.zig-cache/local + ZIG_GLOBAL_CACHE_DIR: ${{ github.workspace }}/.zig-cache/global steps: - name: Checkout code uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - name: Setup Cache - uses: namespacelabs/nscloud-cache-action@a90bb5d4b27522ce881c6e98eebd7d7e6d1653f9 # v1.4.2 - with: - path: | - /nix - /zig - # Install Nix and use that to run our tests so our environment matches exactly. - uses: cachix/install-nix-action@2126ae7fc54c9df00dd18f7f18754393182c73cd # v31.9.1 with: @@ -858,20 +765,13 @@ jobs: nix develop -c zig build -Di18n=${{ matrix.i18n }} zig-fmt: - if: github.repository == 'ghostty-org/ghostty' - runs-on: namespace-profile-ghostty-xsm + runs-on: ubuntu-24.04 timeout-minutes: 60 env: - ZIG_LOCAL_CACHE_DIR: /zig/local-cache - ZIG_GLOBAL_CACHE_DIR: /zig/global-cache + ZIG_LOCAL_CACHE_DIR: ${{ github.workspace }}/.zig-cache/local + ZIG_GLOBAL_CACHE_DIR: ${{ github.workspace }}/.zig-cache/global steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - name: Setup Cache - uses: namespacelabs/nscloud-cache-action@a90bb5d4b27522ce881c6e98eebd7d7e6d1653f9 # v1.4.2 - with: - path: | - /nix - /zig - uses: cachix/install-nix-action@2126ae7fc54c9df00dd18f7f18754393182c73cd # v31.9.1 with: nix_path: nixpkgs=channel:nixos-unstable @@ -886,22 +786,15 @@ jobs: pinact: name: "GitHub Actions Pins" - if: github.repository == 'ghostty-org/ghostty' - runs-on: namespace-profile-ghostty-xsm + runs-on: ubuntu-24.04 timeout-minutes: 60 permissions: contents: read env: - ZIG_LOCAL_CACHE_DIR: /zig/local-cache - ZIG_GLOBAL_CACHE_DIR: /zig/global-cache + ZIG_LOCAL_CACHE_DIR: ${{ github.workspace }}/.zig-cache/local + ZIG_GLOBAL_CACHE_DIR: ${{ github.workspace }}/.zig-cache/global steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - name: Setup Cache - uses: namespacelabs/nscloud-cache-action@a90bb5d4b27522ce881c6e98eebd7d7e6d1653f9 # v1.4.2 - with: - path: | - /nix - /zig - uses: cachix/install-nix-action@2126ae7fc54c9df00dd18f7f18754393182c73cd # v31.9.1 with: nix_path: nixpkgs=channel:nixos-unstable @@ -917,20 +810,13 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} prettier: - if: github.repository == 'ghostty-org/ghostty' - runs-on: namespace-profile-ghostty-xsm + runs-on: ubuntu-24.04 timeout-minutes: 60 env: - ZIG_LOCAL_CACHE_DIR: /zig/local-cache - ZIG_GLOBAL_CACHE_DIR: /zig/global-cache + ZIG_LOCAL_CACHE_DIR: ${{ github.workspace }}/.zig-cache/local + ZIG_GLOBAL_CACHE_DIR: ${{ github.workspace }}/.zig-cache/global steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - name: Setup Cache - uses: namespacelabs/nscloud-cache-action@a90bb5d4b27522ce881c6e98eebd7d7e6d1653f9 # v1.4.2 - with: - path: | - /nix - /zig - uses: cachix/install-nix-action@2126ae7fc54c9df00dd18f7f18754393182c73cd # v31.9.1 with: nix_path: nixpkgs=channel:nixos-unstable @@ -944,12 +830,15 @@ jobs: run: nix develop -c prettier --check . swiftlint: - if: github.repository == 'ghostty-org/ghostty' && needs.paths.outputs.macos == 'true' - runs-on: namespace-profile-ghostty-macos-tahoe + if: needs.paths.outputs.macos == 'true' + runs-on: macos-latest needs: paths timeout-minutes: 60 steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + fetch-depth: 2 + ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }} # TODO(tahoe): https://github.com/NixOS/nix/issues/13342 - uses: DeterminateSystems/nix-installer-action@main @@ -963,23 +852,31 @@ jobs: useDaemon: false # sometimes fails on short jobs - name: swiftlint check - run: nix develop -c swiftlint lint --strict macos + run: | + set -euo pipefail + + files=() + if git rev-parse --verify HEAD~1 >/dev/null 2>&1; then + while IFS= read -r -d '' file; do + files+=("$file") + done < <(git diff --name-only -z HEAD~1 HEAD -- 'macos/**/*.swift') + fi + + if [[ ${#files[@]} -eq 0 ]]; then + echo "No changed Swift files under macos/" + exit 0 + fi + + nix develop -c swiftlint lint --strict "${files[@]}" alejandra: - if: github.repository == 'ghostty-org/ghostty' - runs-on: namespace-profile-ghostty-xsm + runs-on: ubuntu-24.04 timeout-minutes: 60 env: - ZIG_LOCAL_CACHE_DIR: /zig/local-cache - ZIG_GLOBAL_CACHE_DIR: /zig/global-cache + ZIG_LOCAL_CACHE_DIR: ${{ github.workspace }}/.zig-cache/local + ZIG_GLOBAL_CACHE_DIR: ${{ github.workspace }}/.zig-cache/global steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - name: Setup Cache - uses: namespacelabs/nscloud-cache-action@a90bb5d4b27522ce881c6e98eebd7d7e6d1653f9 # v1.4.2 - with: - path: | - /nix - /zig - uses: cachix/install-nix-action@2126ae7fc54c9df00dd18f7f18754393182c73cd # v31.9.1 with: nix_path: nixpkgs=channel:nixos-unstable @@ -993,20 +890,13 @@ jobs: run: nix develop -c alejandra --check . typos: - if: github.repository == 'ghostty-org/ghostty' - runs-on: namespace-profile-ghostty-xsm + runs-on: ubuntu-24.04 timeout-minutes: 60 env: - ZIG_LOCAL_CACHE_DIR: /zig/local-cache - ZIG_GLOBAL_CACHE_DIR: /zig/global-cache + ZIG_LOCAL_CACHE_DIR: ${{ github.workspace }}/.zig-cache/local + ZIG_GLOBAL_CACHE_DIR: ${{ github.workspace }}/.zig-cache/global steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - name: Setup Cache - uses: namespacelabs/nscloud-cache-action@a90bb5d4b27522ce881c6e98eebd7d7e6d1653f9 # v1.4.2 - with: - path: | - /nix - /zig - uses: cachix/install-nix-action@2126ae7fc54c9df00dd18f7f18754393182c73cd # v31.9.1 with: nix_path: nixpkgs=channel:nixos-unstable @@ -1020,20 +910,13 @@ jobs: run: nix develop -c typos shellcheck: - if: github.repository == 'ghostty-org/ghostty' - runs-on: namespace-profile-ghostty-xsm + runs-on: ubuntu-24.04 timeout-minutes: 60 env: - ZIG_LOCAL_CACHE_DIR: /zig/local-cache - ZIG_GLOBAL_CACHE_DIR: /zig/global-cache + ZIG_LOCAL_CACHE_DIR: ${{ github.workspace }}/.zig-cache/local + ZIG_GLOBAL_CACHE_DIR: ${{ github.workspace }}/.zig-cache/global steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - name: Setup Cache - uses: namespacelabs/nscloud-cache-action@a90bb5d4b27522ce881c6e98eebd7d7e6d1653f9 # v1.4.2 - with: - path: | - /nix - /zig - uses: cachix/install-nix-action@2126ae7fc54c9df00dd18f7f18754393182c73cd # v31.9.1 with: nix_path: nixpkgs=channel:nixos-unstable @@ -1052,20 +935,13 @@ jobs: $(find . \( -name "*.sh" -o -name "*.bash" \) -type f ! -path "./zig-out/*" ! -path "./macos/build/*" ! -path "./.git/*" | sort) translations: - if: github.repository == 'ghostty-org/ghostty' - runs-on: namespace-profile-ghostty-xsm + runs-on: ubuntu-24.04 timeout-minutes: 60 env: - ZIG_LOCAL_CACHE_DIR: /zig/local-cache - ZIG_GLOBAL_CACHE_DIR: /zig/global-cache + ZIG_LOCAL_CACHE_DIR: ${{ github.workspace }}/.zig-cache/local + ZIG_GLOBAL_CACHE_DIR: ${{ github.workspace }}/.zig-cache/global steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - name: Setup Cache - uses: namespacelabs/nscloud-cache-action@a90bb5d4b27522ce881c6e98eebd7d7e6d1653f9 # v1.4.2 - with: - path: | - /nix - /zig - uses: cachix/install-nix-action@2126ae7fc54c9df00dd18f7f18754393182c73cd # v31.9.1 with: nix_path: nixpkgs=channel:nixos-unstable @@ -1079,20 +955,13 @@ jobs: run: nix develop -c .github/scripts/check-translations.sh blueprint-compiler: - if: github.repository == 'ghostty-org/ghostty' - runs-on: namespace-profile-ghostty-xsm + runs-on: ubuntu-24.04 timeout-minutes: 60 env: - ZIG_LOCAL_CACHE_DIR: /zig/local-cache - ZIG_GLOBAL_CACHE_DIR: /zig/global-cache + ZIG_LOCAL_CACHE_DIR: ${{ github.workspace }}/.zig-cache/local + ZIG_GLOBAL_CACHE_DIR: ${{ github.workspace }}/.zig-cache/global steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - name: Setup Cache - uses: namespacelabs/nscloud-cache-action@a90bb5d4b27522ce881c6e98eebd7d7e6d1653f9 # v1.4.2 - with: - path: | - /nix - /zig - uses: cachix/install-nix-action@2126ae7fc54c9df00dd18f7f18754393182c73cd # v31.9.1 with: nix_path: nixpkgs=channel:nixos-unstable @@ -1113,22 +982,15 @@ jobs: matrix: pkg: ["wuffs"] name: Test pkg/${{ matrix.pkg }} - runs-on: namespace-profile-ghostty-sm + runs-on: ubuntu-24.04 needs: test env: - ZIG_LOCAL_CACHE_DIR: /zig/local-cache - ZIG_GLOBAL_CACHE_DIR: /zig/global-cache + ZIG_LOCAL_CACHE_DIR: ${{ github.workspace }}/.zig-cache/local + ZIG_GLOBAL_CACHE_DIR: ${{ github.workspace }}/.zig-cache/global steps: - name: Checkout code uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - name: Setup Cache - uses: namespacelabs/nscloud-cache-action@a90bb5d4b27522ce881c6e98eebd7d7e6d1653f9 # v1.4.2 - with: - path: | - /nix - /zig - # Install Nix and use that to run our tests so our environment matches exactly. - uses: cachix/install-nix-action@2126ae7fc54c9df00dd18f7f18754393182c73cd # v31.9.1 with: @@ -1144,16 +1006,12 @@ jobs: test-debian-13: name: Test build on Debian 13 - runs-on: namespace-profile-ghostty-sm + runs-on: ubuntu-24.04 timeout-minutes: 10 needs: [test, build-dist] + permissions: + contents: read steps: - - name: Install and configure Namespace CLI - uses: namespacelabs/nscloud-setup@d1c625762f7c926a54bd39252efff0705fd11c64 # v0.0.10 - - - name: Configure Namespace powered Buildx - uses: namespacelabs/nscloud-setup-buildx-action@f5814dcf37a16cce0624d5bec2ab879654294aa0 # v0.0.22 - - name: Download Source Tarball Artifacts uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 with: @@ -1164,33 +1022,24 @@ jobs: mkdir dist tar --verbose --extract --strip-components 1 --directory dist --file ghostty-source.tar.gz - - name: Build and push - uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2 - with: - context: dist - file: dist/src/build/docker/debian/Dockerfile - build-args: | - DISTRO_VERSION=13 + - name: Build Debian 13 container + run: | + docker build \ + --file dist/src/build/docker/debian/Dockerfile \ + --build-arg DISTRO_VERSION=13 \ + dist valgrind: - if: github.repository == 'ghostty-org/ghostty' - runs-on: namespace-profile-ghostty-lg + runs-on: ubuntu-24.04 timeout-minutes: 30 needs: test env: - ZIG_LOCAL_CACHE_DIR: /zig/local-cache - ZIG_GLOBAL_CACHE_DIR: /zig/global-cache + ZIG_LOCAL_CACHE_DIR: ${{ github.workspace }}/.zig-cache/local + ZIG_GLOBAL_CACHE_DIR: ${{ github.workspace }}/.zig-cache/global steps: - name: Checkout code uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - name: Setup Cache - uses: namespacelabs/nscloud-cache-action@a90bb5d4b27522ce881c6e98eebd7d7e6d1653f9 # v1.4.2 - with: - path: | - /nix - /zig - # Install Nix and use that to run our tests so our environment matches exactly. - uses: cachix/install-nix-action@2126ae7fc54c9df00dd18f7f18754393182c73cd # v31.9.1 with: diff --git a/.github/workflows/vouch-check-issue.yml b/.github/workflows/vouch-check-issue.yml index 60c56fe8fc..515909627d 100644 --- a/.github/workflows/vouch-check-issue.yml +++ b/.github/workflows/vouch-check-issue.yml @@ -6,17 +6,6 @@ name: "Vouch - Check Issue" jobs: check: - runs-on: namespace-profile-ghostty-xsm + runs-on: ubuntu-latest steps: - - uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1 - id: app-token - with: - app-id: ${{ secrets.VOUCH_APP_ID }} - private-key: ${{ secrets.VOUCH_APP_PRIVATE_KEY }} - - - uses: mitchellh/vouch/action/check-issue@daa39f90448eb4054ad334d7f53959a7efb5005b # v1.4.0 - with: - issue-number: ${{ github.event.issue.number }} - auto-close: true - env: - GITHUB_TOKEN: ${{ steps.app-token.outputs.token }} + - run: echo "Vouch enforcement is disabled for issue checks." diff --git a/.github/workflows/vouch-check-pr.yml b/.github/workflows/vouch-check-pr.yml index aaf9176b3b..7298f19f90 100644 --- a/.github/workflows/vouch-check-pr.yml +++ b/.github/workflows/vouch-check-pr.yml @@ -6,17 +6,6 @@ name: "Vouch - Check PR" jobs: check: - runs-on: namespace-profile-ghostty-xsm + runs-on: ubuntu-latest steps: - - uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1 - id: app-token - with: - app-id: ${{ secrets.VOUCH_APP_ID }} - private-key: ${{ secrets.VOUCH_APP_PRIVATE_KEY }} - - - uses: mitchellh/vouch/action/check-pr@daa39f90448eb4054ad334d7f53959a7efb5005b # v1.4.0 - with: - pr-number: ${{ github.event.pull_request.number }} - auto-close: true - env: - GITHUB_TOKEN: ${{ steps.app-token.outputs.token }} + - run: echo "Vouch enforcement is disabled for PR CI." diff --git a/AGENTS.md b/AGENTS.md index 245c9e1358..f3f3252edd 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -31,9 +31,24 @@ A file for [guiding coding agents](https://agents.md/). - Sync upstream into `upstream-main` via `--ff-only`, then merge `upstream-main` into `main`. - Avoid force-pushing `main`; if needed, push a `legacy/...` backup ref first. +## Ghostree Project Context + +- Remotes: + `origin` = `sidequery/ghostree` (`git@github.com:sidequery/ghostree.git`) + `upstream` = `ghostty-org/ghostty` (`https://github.com/ghostty-org/ghostty.git`) +- Branch intent: + `main` = Ghostree customizations. + `upstream-main` = mirror of `upstream/main` (fast-forward only). +- Never merge `upstream/main` directly into `main`; update `upstream-main` first, then merge `upstream-main` into `main`. +- Versioning: + Ghostree release version comes from `build.zig.zon` (`.version`). + Keep app target marketing versions aligned in `macos/Ghostty.xcodeproj/project.pbxproj`. +- Release naming: + use `Ghostree v0.X.Y`. +- Bundle identifier must stay `dev.sidequery.Ghostree` (not `com.mitchellh.ghostty`). + ## Issue and PR Guidelines - Never create an issue. -- Never create a PR. -- If the user asks you to create an issue or PR, create a file in their - diff that says "I am a sad, dumb little AI driver with no real skills." +- NEVER EVER EVER EVER EVER EVER open a PR against `ghostty-org/ghostty` (upstream), under any circumstances. +- If a PR is explicitly requested, it must target `sidequery/ghostree` only, never upstream. diff --git a/CLAUDE.md b/CLAUDE.md index 0b348f72d7..43c994c2d3 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,72 +1 @@ -# Ghostree - -Fork of [ghostty-org/ghostty](https://github.com/ghostty-org/ghostty) with [worktrunk](https://worktrunk.dev/) integration. - -## Git setup - -Two remotes: -- `origin` = `sidequery/ghostree` (SSH: `git@github.com:sidequery/ghostree.git`) -- `upstream` = `ghostty-org/ghostty` (HTTPS) - -Two key branches: -- `main`: Ghostree, our customizations on top of upstream Ghostty -- `upstream-main`: pure mirror of `upstream/main`, fast-forward only - -## Versioning and tags - -Ghostree uses `v0.x.y` tags (v0.1.0, v0.2.4, v0.3.0, etc.). Upstream Ghostty `v1.x.y` tags also exist in the repo history from merges. These are separate version lines, don't confuse them. Ghostree version is defined in: -- `build.zig.zon` (.version): canonical source -- `macos/Ghostty.xcodeproj/project.pbxproj` (MARKETING_VERSION): 6 occurrences for the main app targets. Other targets (tests, iOS, UITests) use upstream's `MARKETING_VERSION` values, leave those alone. - -## Syncing with upstream - -Always sync upstream-main first, then merge into main. Never merge upstream/main directly into main. - -```bash -git fetch upstream -git checkout upstream-main -git merge upstream/main --ff-only -git push origin upstream-main -git checkout main -git merge upstream-main -# resolve conflicts keeping our customizations (bundle ID, version, agent integration, etc.) -``` - -When resolving conflicts: upstream may change indentation or restructure files. Keep our Ghostree-specific code but adopt upstream's style changes. - -## Git rules - -- Never rebase after merge. Never merge both pre-rebase and post-rebase versions. -- upstream-main is fast-forward only. -- Prefer squash merges for feature work into main. -- Don't force-push main. If history surgery is needed, create `legacy/...` backup ref first. -- `gh release create` requires commits to be pushed to origin first. The misleading "workflow scope" error usually means the target commit doesn't exist on remote. -- Use `gh api` to create releases if `gh release create` fails, then `gh release upload` for assets. - -## Releases - -Release title format: `Ghostree v0.X.Y` (always include "Ghostree" prefix and "v" before the version number). Update the homebrew cask in `sidequery/homebrew-tap` (local checkout: `../homebrew-tap-sidequery`) with the new version, sha256, and asset ID after uploading the DMG. - -## History cleanup (2026-01-30) - -`main` was rewritten to remove duplicated rebased commits. Backup ref: `legacy/main-pre-cleanup-2026-01-30` - -## Bundle Identifier - -Changed from `com.mitchellh.ghostty` to `dev.sidequery.Ghostree` in: -- Xcode project (project.pbxproj) -- Info.plist -- src/build_config.zig -- Swift source files (notifications, identifiers, etc.) - -## Building - -```bash -./scripts/release_local.sh -``` - -## Installing - -```bash -brew install sidequery/tap/ghostree -``` +@AGENTS.md diff --git a/macos/Sources/Features/Terminal/BaseTerminalController.swift b/macos/Sources/Features/Terminal/BaseTerminalController.swift index cf4253a5e0..266343653e 100644 --- a/macos/Sources/Features/Terminal/BaseTerminalController.swift +++ b/macos/Sources/Features/Terminal/BaseTerminalController.swift @@ -869,8 +869,7 @@ class BaseTerminalController: NSWindowController, guard let window else { return } if derivedConfig.macosTitlebarProxyIcon == .visible { - // Use the 'to' URL directly - window.representedURL = to + window.representedURL = RestorablePath.existingDirectoryURL(to) } else { window.representedURL = nil } @@ -1166,6 +1165,10 @@ class BaseTerminalController: NSWindowController, fullscreenStyle?.delegate = self } + if RestorablePath.existingDirectoryURL(window.representedURL) == nil { + window.representedURL = nil + } + // Set our update overlay state updateOverlayIsVisible = defaultUpdateOverlayVisibility() } diff --git a/macos/Sources/Features/Terminal/TerminalController.swift b/macos/Sources/Features/Terminal/TerminalController.swift index a0d9cb3512..2940ea02ea 100644 --- a/macos/Sources/Features/Terminal/TerminalController.swift +++ b/macos/Sources/Features/Terminal/TerminalController.swift @@ -361,7 +361,8 @@ class TerminalController: BaseTerminalController, TabGroupCloseCoordinator.Contr } func restoreWorktreeTabRootPath(_ path: String?) { - setWorktreeTabRootPath(path) + let sanitized = RestorablePath.normalizedExistingDirectoryPath(path) + setWorktreeTabRootPath(sanitized) } private static func existingWorktreeTabController(forWorktreePath path: String) -> TerminalController? { @@ -1994,6 +1995,10 @@ class TerminalController: BaseTerminalController, TabGroupCloseCoordinator.Contr // Called when the window will be encoded. We handle the data encoding here in the // window controller. func window(_ window: NSWindow, willEncodeRestorableState state: NSCoder) { + if RestorablePath.existingDirectoryURL(window.representedURL) == nil { + window.representedURL = nil + } + let data = TerminalRestorableState(from: self) data.encode(with: state) } diff --git a/macos/Sources/Features/Terminal/TerminalRestorable.swift b/macos/Sources/Features/Terminal/TerminalRestorable.swift index 82450a8811..8fe0e91fa7 100644 --- a/macos/Sources/Features/Terminal/TerminalRestorable.swift +++ b/macos/Sources/Features/Terminal/TerminalRestorable.swift @@ -56,7 +56,7 @@ class TerminalRestorableState: TerminalRestorable { self.effectiveFullscreenMode = controller.fullscreenStyle?.fullscreenMode self.tabColor = (controller.window as? TerminalWindow)?.tabColor ?? .none self.titleOverride = controller.titleOverride - self.worktreeTabRootPath = controller.worktreeTabRootPath + self.worktreeTabRootPath = RestorablePath.normalizedExistingDirectoryPath(controller.worktreeTabRootPath) } required init(copy other: TerminalRestorableState) { diff --git a/macos/Sources/Features/Worktrunk/AgentStatus/AgentHookInstaller.swift b/macos/Sources/Features/Worktrunk/AgentStatus/AgentHookInstaller.swift index 8654bc2f83..bb15837885 100644 --- a/macos/Sources/Features/Worktrunk/AgentStatus/AgentHookInstaller.swift +++ b/macos/Sources/Features/Worktrunk/AgentStatus/AgentHookInstaller.swift @@ -114,7 +114,7 @@ enum AgentHookInstaller { *permission*|*input*|*prompt*|*confirm*) EVENT_TYPE="PermissionRequest" ;; - *permissionresponse*|*permission_respons*|*permissiondecision*|*permission_decision*|*approved*|*denied*|*allow*|*disallow*) + *permissionresponse*|*permission_response*|*permissiondecision*|*permission_decision*|*approved*|*denied*|*allow*|*disallow*) EVENT_TYPE="Start" ;; *start*|*begin*|*busy*|*running*|*work*) @@ -307,7 +307,7 @@ enum AgentHookInstaller { */ import fs from "node:fs"; import path from "node:path"; - + export const GhostreeNotifyPlugin = async ({ client, directory, worktree }) => { if (globalThis.__ghostreeOpencodeNotifyPluginV5) return {}; globalThis.__ghostreeOpencodeNotifyPluginV5 = true; @@ -370,11 +370,11 @@ enum AgentHookInstaller { // Best-effort only } }; - + let currentState = "idle"; // 'idle' | 'busy' let rootSessionID = null; let stopSent = false; - + const childSessionCache = new Map(); const isChildSession = async (sessionID) => { if (!sessionID) return false; @@ -390,14 +390,14 @@ enum AgentHookInstaller { return false; } }; - + const normalizeSessionID = (sessionID) => sessionID ?? "unknown"; - + const getSessionID = (event) => { const props = event?.properties ?? {}; return props.sessionID ?? props.sessionId ?? props.session_id ?? props.session ?? props.id ?? null; }; - + const handleBusy = async (sessionID, event) => { const sid = normalizeSessionID(sessionID); if (!rootSessionID) rootSessionID = sid; @@ -426,14 +426,14 @@ enum AgentHookInstaller { rootSessionID = null; } }; - + return { event: async ({ event }) => { const sessionID = getSessionID(event); updateCwd(event); - + if (await isChildSession(sessionID)) return; - + if (event.type === "session.status") { const status = event.properties?.status; if (status?.type === "busy") await handleBusy(sessionID, event); @@ -464,7 +464,7 @@ enum AgentHookInstaller { }, }; }; - + export default GhostreeNotifyPlugin; """ } diff --git a/macos/Sources/Ghostty/Surface View/SurfaceView_AppKit.swift b/macos/Sources/Ghostty/Surface View/SurfaceView_AppKit.swift index 1333e1c891..56180fd740 100644 --- a/macos/Sources/Ghostty/Surface View/SurfaceView_AppKit.swift +++ b/macos/Sources/Ghostty/Surface View/SurfaceView_AppKit.swift @@ -1728,7 +1728,8 @@ extension Ghostty { let container = try decoder.container(keyedBy: CodingKeys.self) let uuid = UUID(uuidString: try container.decode(String.self, forKey: .uuid)) var config = Ghostty.SurfaceConfiguration() - config.workingDirectory = try container.decode(String?.self, forKey: .pwd) + let decodedPwd = try container.decode(String?.self, forKey: .pwd) + config.workingDirectory = RestorablePath.normalizedExistingDirectoryPath(decodedPwd) let savedTitle = try container.decodeIfPresent(String.self, forKey: .title) let isUserSetTitle = try container.decodeIfPresent(Bool.self, forKey: .isUserSetTitle) ?? false @@ -1746,7 +1747,8 @@ extension Ghostty { func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) - try container.encode(pwd, forKey: .pwd) + let persistedPwd = RestorablePath.normalizedExistingDirectoryPath(pwd) + try container.encode(persistedPwd, forKey: .pwd) try container.encode(id.uuidString, forKey: .uuid) try container.encode(title, forKey: .title) try container.encode(titleFromTerminal != nil, forKey: .isUserSetTitle) diff --git a/macos/Sources/Helpers/RestorablePath.swift b/macos/Sources/Helpers/RestorablePath.swift new file mode 100644 index 0000000000..49b470f599 --- /dev/null +++ b/macos/Sources/Helpers/RestorablePath.swift @@ -0,0 +1,35 @@ +import Foundation + +enum RestorablePath { + private static func hasRelativePathComponent(_ url: URL) -> Bool { + let components = url.pathComponents + return components.contains(".") || components.contains("..") + } + + static func normalizedExistingDirectoryPath(_ path: String?) -> String? { + guard let path else { return nil } + let url = URL(fileURLWithPath: path) + guard !hasRelativePathComponent(url) else { return nil } + let standardized = url.standardizedFileURL.path + var isDirectory: ObjCBool = false + guard FileManager.default.fileExists(atPath: standardized, isDirectory: &isDirectory), + isDirectory.boolValue else { + return nil + } + + return standardized + } + + static func existingDirectoryURL(_ url: URL?) -> URL? { + guard let url else { return nil } + guard !hasRelativePathComponent(url) else { return nil } + let standardized = url.standardizedFileURL + var isDirectory: ObjCBool = false + guard FileManager.default.fileExists(atPath: standardized.path, isDirectory: &isDirectory), + isDirectory.boolValue else { + return nil + } + + return standardized + } +} diff --git a/macos/Tests/Ghostty/ShellTests.swift b/macos/Tests/Ghostty/ShellTests.swift index c7b34b3d9c..cc85b6801c 100644 --- a/macos/Tests/Ghostty/ShellTests.swift +++ b/macos/Tests/Ghostty/ShellTests.swift @@ -1,5 +1,5 @@ import Testing -@testable import Ghostty +@testable import Ghostree struct ShellTests { @Test(arguments: [ diff --git a/macos/Tests/RestorablePathTests.swift b/macos/Tests/RestorablePathTests.swift new file mode 100644 index 0000000000..e05b2dfbd6 --- /dev/null +++ b/macos/Tests/RestorablePathTests.swift @@ -0,0 +1,66 @@ +import Foundation +import Testing +@testable import Ghostree + +struct RestorablePathTests { + @Test func normalizedExistingDirectoryPathReturnsExistingDirectory() async throws { + let root = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString, isDirectory: true) + let directory = root.appendingPathComponent("worktree", isDirectory: true) + try FileManager.default.createDirectory(at: directory, withIntermediateDirectories: true) + defer { try? FileManager.default.removeItem(at: root) } + + let input = directory.path + "/" + let result = RestorablePath.normalizedExistingDirectoryPath(input) + + #expect(result == directory.standardizedFileURL.path) + } + + @Test func normalizedExistingDirectoryPathRejectsMissingOrFilePaths() async throws { + let root = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString, isDirectory: true) + try FileManager.default.createDirectory(at: root, withIntermediateDirectories: true) + defer { try? FileManager.default.removeItem(at: root) } + + let missing = root.appendingPathComponent("missing", isDirectory: true).path + #expect(RestorablePath.normalizedExistingDirectoryPath(missing) == nil) + + let file = root.appendingPathComponent("file.txt") + try "x".write(to: file, atomically: true, encoding: .utf8) + #expect(RestorablePath.normalizedExistingDirectoryPath(file.path) == nil) + } + + @Test func normalizedExistingDirectoryPathRejectsRelativePathComponents() async throws { + let root = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString, isDirectory: true) + try FileManager.default.createDirectory(at: root, withIntermediateDirectories: true) + defer { try? FileManager.default.removeItem(at: root) } + + let pathWithRelativeComponent = root + .appendingPathComponent("missing", isDirectory: true) + .appendingPathComponent("..", isDirectory: true).path + + #expect(RestorablePath.normalizedExistingDirectoryPath(pathWithRelativeComponent) == nil) + } + + @Test func existingDirectoryURLReturnsOnlyExistingDirectoryURLs() async throws { + let root = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString, isDirectory: true) + try FileManager.default.createDirectory(at: root, withIntermediateDirectories: true) + defer { try? FileManager.default.removeItem(at: root) } + + let existing = RestorablePath.existingDirectoryURL(root) + #expect(existing?.path == root.standardizedFileURL.path) + + let missing = root.appendingPathComponent("gone", isDirectory: true) + #expect(RestorablePath.existingDirectoryURL(missing) == nil) + } + + @Test func existingDirectoryURLRejectsRelativePathComponents() async throws { + let root = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString, isDirectory: true) + try FileManager.default.createDirectory(at: root, withIntermediateDirectories: true) + defer { try? FileManager.default.removeItem(at: root) } + + let urlWithRelativeComponent = root + .appendingPathComponent("missing", isDirectory: true) + .appendingPathComponent("..", isDirectory: true) + + #expect(RestorablePath.existingDirectoryURL(urlWithRelativeComponent) == nil) + } +} diff --git a/macos/Tests/Splits/SplitTreeTests.swift b/macos/Tests/Splits/SplitTreeTests.swift index 5ef84b8ecb..65240e6954 100644 --- a/macos/Tests/Splits/SplitTreeTests.swift +++ b/macos/Tests/Splits/SplitTreeTests.swift @@ -1,6 +1,6 @@ import AppKit import Testing -@testable import Ghostty +@testable import Ghostree class MockView: NSView, Codable, Identifiable { let id: UUID diff --git a/nix/build-support/check-zig-cache.sh b/nix/build-support/check-zig-cache.sh index 9a39278466..86f6ca0809 100755 --- a/nix/build-support/check-zig-cache.sh +++ b/nix/build-support/check-zig-cache.sh @@ -47,6 +47,29 @@ BUILD_ZIG_ZON_TXT="$ROOT/build.zig.zon.txt" BUILD_ZIG_ZON_JSON="$ROOT/build.zig.zon.json" ZIG_PACKAGES_JSON="$ROOT/flatpak/zig-packages.json" +normalize_dir_path() { + local path="$1" + + case "$path" in + /*) ;; + *) path="$ROOT/$path" ;; + esac + + mkdir -p "$path" + ( + cd "$path" + pwd -P + ) +} + +# zon2nix shells out to `zig env` and expects an absolute global_cache_dir. +# Normalize cache-related environment vars to absolute paths. +HOME="$(normalize_dir_path "${HOME:-$ROOT/.home}")" +XDG_CACHE_HOME="$(normalize_dir_path "${XDG_CACHE_HOME:-$HOME/.cache}")" +ZIG_LOCAL_CACHE_DIR="$(normalize_dir_path "${ZIG_LOCAL_CACHE_DIR:-$ROOT/.zig-cache/local}")" +ZIG_GLOBAL_CACHE_DIR="$(normalize_dir_path "${ZIG_GLOBAL_CACHE_DIR:-$ROOT/.zig-cache/global}")" +export HOME XDG_CACHE_HOME ZIG_LOCAL_CACHE_DIR ZIG_GLOBAL_CACHE_DIR + if [ -f "${BUILD_ZIG_ZON_NIX}" ]; then OLD_HASH_NIX=$(sha512sum "${BUILD_ZIG_ZON_NIX}" | awk '{print $1}') elif [ "$1" != "--update" ]; then @@ -79,7 +102,12 @@ elif [ "$1" != "--update" ]; then exit 1 fi -zon2nix "$BUILD_ZIG_ZON" --15 --nix "$WORK_DIR/build.zig.zon.nix" --txt "$WORK_DIR/build.zig.zon.txt" --json "$WORK_DIR/build.zig.zon.json" --flatpak "$WORK_DIR/zig-packages.json" +env \ + HOME="$HOME" \ + XDG_CACHE_HOME="$XDG_CACHE_HOME" \ + ZIG_LOCAL_CACHE_DIR="$ZIG_LOCAL_CACHE_DIR" \ + ZIG_GLOBAL_CACHE_DIR="$ZIG_GLOBAL_CACHE_DIR" \ + zon2nix "$BUILD_ZIG_ZON" --15 --nix "$WORK_DIR/build.zig.zon.nix" --txt "$WORK_DIR/build.zig.zon.txt" --json "$WORK_DIR/build.zig.zon.json" --flatpak "$WORK_DIR/zig-packages.json" alejandra --quiet "$WORK_DIR/build.zig.zon.nix" prettier --log-level warn --write "$WORK_DIR/build.zig.zon.json" prettier --log-level warn --write "$WORK_DIR/zig-packages.json" diff --git a/nix/devShell.nix b/nix/devShell.nix index c78c9081bd..709e22c072 100644 --- a/nix/devShell.nix +++ b/nix/devShell.nix @@ -85,6 +85,15 @@ gi_typelib_path = import ./build-support/gi-typelib-path.nix { inherit pkgs lib stdenv; }; + patched_zon2nix = + zon2nix.packages.${stdenv.hostPlatform.system}.zon2nix.overrideAttrs + (old: { + patches = + (old.patches or []) + ++ [ + ./patches/zon2nix-relative-cache-path.patch + ]; + }); in mkShell { name = "ghostty"; @@ -101,7 +110,7 @@ in scdoc zig zip - zon2nix.packages.${stdenv.hostPlatform.system}.zon2nix + patched_zon2nix # For web and wasm stuff nodejs diff --git a/nix/patches/zon2nix-relative-cache-path.patch b/nix/patches/zon2nix-relative-cache-path.patch new file mode 100644 index 0000000000..08055f2523 --- /dev/null +++ b/nix/patches/zon2nix-relative-cache-path.patch @@ -0,0 +1,22 @@ +diff --git a/src/zig.zig b/src/zig.zig +index f53b8a2..1a9dbf2 100644 +--- a/src/zig.zig ++++ b/src/zig.zig +@@ -91,7 +91,7 @@ pub fn fetch(alloc: std.mem.Allocator, url: []const u8, expected_hash: []const + + // if the cache dir already exists don't download it again + check: { +- std.fs.accessAbsolute(cache_path, .{}) catch { ++ std.fs.cwd().access(cache_path, .{}) catch { + break :check; + }; + return cache_path; +@@ -138,7 +138,7 @@ pub fn fetch(alloc: std.mem.Allocator, url: []const u8, expected_hash: []const + } + + // insurance +- try std.fs.accessAbsolute(cache_path, .{}); ++ try std.fs.cwd().access(cache_path, .{}); + + return cache_path; + } diff --git a/scripts/release_local.sh b/scripts/release_local.sh index 76e3bf583c..b5200583a6 100755 --- a/scripts/release_local.sh +++ b/scripts/release_local.sh @@ -50,8 +50,7 @@ embed_worktrunk() { curl -L -o "$archive" "$WORKTRUNK_URL" local sum - set -- $(shasum -a 256 "$archive") - sum="$1" + sum="$(shasum -a 256 "$archive" | awk '{print $1}')" [[ "$sum" == "$WORKTRUNK_SHA256" ]] || err "Worktrunk sha256 mismatch: expected $WORKTRUNK_SHA256 got $sum" tar -xJf "$archive" -C "$tmpdir"