Repository navigation
feat(mobile): Android companion and debug validation CI #2266
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: PR Build Validation | |
| on: | |
| pull_request: | |
| types: | |
| - opened | |
| - edited | |
| - synchronize | |
| - reopened | |
| - ready_for_review | |
| permissions: | |
| contents: read | |
| actions: write | |
| concurrency: | |
| group: pr-build-${{ github.event.pull_request.number }} | |
| cancel-in-progress: true | |
| jobs: | |
| authorize: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| allowed: ${{ steps.auth.outputs.allowed }} | |
| env: | |
| ALLOWED_ACTORS: ${{ vars.ALLOWED_NON_DEV_PR_ACTORS }} | |
| PR_AUTHOR: ${{ github.event.pull_request.user.login }} | |
| BASE_REF: ${{ github.event.pull_request.base.ref }} | |
| steps: | |
| - name: Check PR authorization | |
| id: auth | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| if [ "$BASE_REF" = "dev" ] || [ "$BASE_REF" = "DEV-v2" ]; then | |
| echo "allowed=true" >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| normalized=",${ALLOWED_ACTORS}," | |
| if [[ "$normalized" == *",${PR_AUTHOR},"* ]]; then | |
| echo "allowed=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "allowed=false" >> "$GITHUB_OUTPUT" | |
| echo "Skipping builds for PR by unauthorized author targeting $BASE_REF" >&2 | |
| fi | |
| build: | |
| needs: | |
| - authorize | |
| - tests | |
| - tests-tauri-windows | |
| - tests-opencode-compatibility | |
| - tests-session-pruning-native | |
| - tests-runtime-contracts | |
| - tests-tauri-macos | |
| if: ${{ needs.authorize.outputs.allowed == 'true' && !github.event.pull_request.draft }} | |
| uses: ./.github/workflows/build-and-upload.yml | |
| with: | |
| ref: ${{ github.event.pull_request.head.sha }} | |
| upload: false | |
| upload_actions_artifacts: true | |
| actions_artifacts_retention_days: 7 | |
| actions_artifacts_name_prefix: pr-${{ github.event.pull_request.number }}-${{ github.event.pull_request.head.sha }}- | |
| set_versions: false | |
| tests-session-pruning-native: | |
| needs: authorize | |
| if: ${{ needs.authorize.outputs.allowed == 'true' && !github.event.pull_request.draft }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [windows-latest, ubuntu-latest, macos-latest] | |
| runs-on: ${{ matrix.os }} | |
| timeout-minutes: 15 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ github.event.pull_request.head.sha }} | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version-file: .node-version | |
| cache: npm | |
| - run: npm ci --ignore-scripts | |
| - name: Install browser for native pruning UI checks | |
| run: npx --workspace @codenomad/ui playwright install --with-deps chromium | |
| - name: Pack and install outside the checkout | |
| shell: pwsh | |
| run: | | |
| $sandbox = Join-Path $env:RUNNER_TEMP 'pruning-native-install' | |
| New-Item -ItemType Directory -Force $sandbox | Out-Null | |
| $package = npm pack ./packages/server/src/opencode/session-pruning --pack-destination $sandbox --json | ConvertFrom-Json | |
| if ($LASTEXITCODE) { exit $LASTEXITCODE } | |
| npm install --prefix $sandbox (Join-Path $sandbox $package.filename) '@opencode/cli@latest' --ignore-scripts --no-audit --no-fund | |
| if ($LASTEXITCODE) { exit $LASTEXITCODE } | |
| "PRUNING_NATIVE_INSTALL=$sandbox" >> $env:GITHUB_ENV | |
| - name: Test the installed plugin with an isolated official runtime | |
| shell: pwsh | |
| run: | | |
| $platform = node -p "process.platform === 'win32' ? 'windows' : process.platform" | |
| $arch = node -p "process.arch" | |
| $extension = node -p "process.platform === 'win32' ? '.exe' : ''" | |
| $cli = Join-Path $env:PRUNING_NATIVE_INSTALL "node_modules/@opencode/cli-$platform-$arch/bin/opencode$extension" | |
| & $cli --version | |
| if ($LASTEXITCODE) { exit $LASTEXITCODE } | |
| $plugin = Join-Path $env:PRUNING_NATIVE_INSTALL 'node_modules/@neuralnomads/codenomad-session-pruning' | |
| $fixtures = node -p "require('node:path').join(require('node:fs').realpathSync(require('node:os').tmpdir()), 'opencode')" | |
| "PRUNING_NATIVE_FIXTURES=$fixtures" >> $env:GITHUB_ENV | |
| node scripts/run-session-pruning-native.mjs $cli $plugin | |
| if ($LASTEXITCODE) { exit $LASTEXITCODE } | |
| npm run build:pruning --workspace @neuralnomads/codenomad | |
| if ($LASTEXITCODE) { exit $LASTEXITCODE } | |
| node --import tsx --test packages/server/src/opencode/pruning-installation.test.ts | |
| if ($LASTEXITCODE) { exit $LASTEXITCODE } | |
| node scripts/run-session-pruning-native.mjs $cli --ui | |
| - name: Upload isolated native failure diagnostics | |
| if: ${{ failure() && env.PRUNING_NATIVE_FIXTURES != '' }} | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: session-pruning-failure-${{ matrix.os }} | |
| path: | | |
| ${{ env.PRUNING_NATIVE_FIXTURES }}/codenomad-pruning-native-*/server.log | |
| ${{ env.PRUNING_NATIVE_FIXTURES }}/codenomad-pruning-native-*/before-restart.log | |
| ${{ env.PRUNING_NATIVE_FIXTURES }}/codenomad-pruning-native-*/discovery.json | |
| ${{ env.PRUNING_NATIVE_FIXTURES }}/codenomad-pruning-native-*/ui-*.png | |
| ${{ env.PRUNING_NATIVE_FIXTURES }}/codenomad-pruning-native-*/test-diagnostics.jsonl | |
| ${{ env.PRUNING_NATIVE_FIXTURES }}/native-fixture-run-*/ | |
| if-no-files-found: ignore | |
| retention-days: 7 | |
| - name: Upload opt-in plugin package | |
| if: success() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: session-pruning-plugin-${{ matrix.os }} | |
| path: ${{ runner.temp }}/pruning-native-install/*.tgz | |
| if-no-files-found: error | |
| retention-days: 7 | |
| tests-runtime-contracts: | |
| needs: authorize | |
| if: ${{ needs.authorize.outputs.allowed == 'true' && !github.event.pull_request.draft }} | |
| runs-on: windows-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| runtime: [minimum, latest] | |
| timeout-minutes: 15 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ github.event.pull_request.head.sha }} | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version-file: .node-version | |
| cache: npm | |
| - run: npm ci --ignore-scripts | |
| - run: npm run build:pruning --workspace @neuralnomads/codenomad | |
| - run: npm run build:automation --workspace @neuralnomads/codenomad | |
| - name: Qualify the pinned client against the technical minimum and latest stable | |
| shell: pwsh | |
| run: | | |
| $sandbox = Join-Path $env:RUNNER_TEMP 'opencode-contract-runtime' | |
| $version = '${{ matrix.runtime }}' | |
| if ($version -eq 'minimum') { | |
| $version = node --import tsx --input-type=module -e "import { MINIMUM_OPENCODE_VERSION } from './packages/server/src/opencode/runtime-support.ts'; console.log(MINIMUM_OPENCODE_VERSION)" | |
| if ($LASTEXITCODE) { exit $LASTEXITCODE } | |
| } | |
| npm install --prefix $sandbox "@opencode/cli@$version" --ignore-scripts --no-audit --no-fund | |
| if ($LASTEXITCODE) { exit $LASTEXITCODE } | |
| $cli = Join-Path $sandbox 'node_modules/@opencode/cli-windows-x64/bin/opencode.exe' | |
| & $cli --version | |
| if ($LASTEXITCODE) { exit $LASTEXITCODE } | |
| node scripts/test-automation-native.mjs $cli | |
| if ($LASTEXITCODE) { exit $LASTEXITCODE } | |
| node scripts/test-session-pruning-native.mjs $cli | |
| if ($LASTEXITCODE) { exit $LASTEXITCODE } | |
| node scripts/test-session-environment-native.mjs $cli | |
| if ($LASTEXITCODE) { exit $LASTEXITCODE } | |
| node scripts/test-session-fork-native.mjs $cli | |
| if ($LASTEXITCODE) { exit $LASTEXITCODE } | |
| node scripts/test-session-aside-native.mjs $cli | |
| if ($LASTEXITCODE) { exit $LASTEXITCODE } | |
| node --conditions=browser --import tsx scripts/test-blank-session-cleanup-native.mjs $cli | |
| if ($LASTEXITCODE) { exit $LASTEXITCODE } | |
| tests: | |
| needs: authorize | |
| if: ${{ needs.authorize.outputs.allowed == 'true' && !github.event.pull_request.draft }} | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ github.event.pull_request.head.sha }} | |
| - name: Setup Node | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version-file: .node-version | |
| cache: npm | |
| - name: Setup Rust | |
| uses: dtolnay/rust-toolchain@stable | |
| - name: Install Linux test dependencies (Tauri) | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y \ | |
| build-essential \ | |
| zsh \ | |
| xvfb \ | |
| pkg-config \ | |
| libgtk-3-dev \ | |
| libglib2.0-dev \ | |
| libwebkit2gtk-4.1-dev \ | |
| libsoup-3.0-dev \ | |
| libayatana-appindicator3-dev \ | |
| librsvg2-dev | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Typecheck desktop clients | |
| run: npm run typecheck | |
| - name: Build bundled automation integration | |
| run: npm run build:automation --workspace @neuralnomads/codenomad | |
| - name: Test desktop packaging invariants | |
| run: node --test scripts/desktop-server-resources.test.cjs scripts/prepare-node-runtime.test.cjs | |
| - name: Test CI fixture diagnostics and artifact announcements | |
| run: node --test scripts/native-fixture-diagnostics.test.mjs .github/scripts/comment-pr-artifacts.test.cjs | |
| - name: Test Electron client state | |
| env: | |
| CODENOMAD_TEST_ZSH: /bin/zsh | |
| run: | | |
| npm run test:native --workspace @neuralnomads/codenomad-electron-app | |
| node --import tsx --test packages/electron-app/electron/main/view-menu.test.ts | |
| - name: Test changed runnable UI behavior | |
| run: >- | |
| node --import tsx --test --test-force-exit | |
| packages/ui/src/components/browser-frame-security.test.ts | |
| packages/ui/src/components/message-history-pagination.test.ts | |
| packages/ui/src/components/message-timeline-v2.test.ts | |
| packages/ui/src/components/session-outline-projection.test.ts | |
| packages/ui/src/components/provider-auth/provider-options.test.ts | |
| packages/ui/src/components/prompt-input/device-file-selection.test.ts | |
| packages/ui/src/components/prompt-input/height-state.test.ts | |
| packages/ui/src/components/session/session-bottom-pin-intent.test.ts | |
| packages/ui/src/components/session/session-idle-attention.test.ts | |
| packages/ui/src/components/session-list-visibility.test.ts | |
| packages/ui/src/components/tool-call/permission-block.test.ts | |
| packages/ui/src/components/tool-call/render-memory.test.ts | |
| packages/ui/src/components/settings/info-settings-diagnostics.test.ts | |
| packages/ui/src/components/tool-call/tool-presentation.test.ts | |
| packages/ui/src/components/transcript-visibility.test.ts | |
| packages/ui/src/components/unified-picker-path.test.ts | |
| packages/ui/src/components/virtual-follow-behavior.test.ts | |
| packages/ui/src/components/virtual-follow-measurements.test.ts | |
| packages/ui/src/components/virtual-reader-settlement.test.ts | |
| packages/ui/src/lib/client-identity.test.ts | |
| packages/ui/src/lib/filesystem-events.test.ts | |
| packages/ui/src/lib/global-cache.test.ts | |
| packages/ui/src/lib/hooks/use-app-session-capture.test.ts | |
| packages/ui/src/lib/hooks/use-instance-metadata.test.ts | |
| packages/ui/src/lib/hooks/use-foreground-refresh.test.ts | |
| packages/ui/src/lib/hooks/use-electron-folder-launch.test.ts | |
| packages/ui/src/lib/launch-errors.test.ts | |
| packages/ui/src/lib/clipboard.test.ts | |
| packages/ui/src/lib/message-selection-position.test.ts | |
| packages/ui/src/lib/model-visibility.test.ts | |
| packages/ui/src/lib/retained-size.test.ts | |
| packages/ui/src/lib/provider-auth.test.ts | |
| packages/ui/src/lib/native/browser.test.ts | |
| packages/ui/src/lib/runtime-env.test.ts | |
| packages/ui/src/lib/session-transcript-lru.test.ts | |
| packages/ui/src/lib/server-meta.test.ts | |
| packages/ui/src/lib/theme-scheme.test.ts | |
| packages/ui/src/lib/trailing-resync.test.ts | |
| packages/ui/src/stores/abort-created-workspace-cleanup.test.ts | |
| packages/ui/src/stores/app-session-reconciliation.test.ts | |
| packages/ui/src/stores/app-session-restore-queue.test.ts | |
| packages/ui/src/stores/app-session-restore-timeout.test.ts | |
| packages/ui/src/stores/app-session-snapshot-merge.test.ts | |
| packages/ui/src/stores/restore-workspace-commit-gates.test.ts | |
| packages/ui/src/stores/client-state-codec.test.ts | |
| packages/ui/src/stores/client-state-partitions.test.ts | |
| packages/ui/src/stores/client-state.test.ts | |
| packages/ui/src/stores/form-settlements.test.ts | |
| packages/ui/src/stores/instance-invalidation.test.ts | |
| packages/ui/src/stores/plugin-controls.test.ts | |
| packages/ui/src/stores/plugin-controls-demand.test.ts | |
| packages/ui/src/stores/plugin-controls-events.test.ts | |
| packages/ui/src/stores/message-prompt-display.test.ts | |
| packages/ui/src/stores/message-v2/instance-store.test.ts | |
| packages/ui/src/stores/message-v2/message-hydration-authority.test.ts | |
| packages/ui/src/stores/message-v2/message-status.test.ts | |
| packages/ui/src/stores/message-v2/message-window.test.ts | |
| packages/ui/src/stores/message-v2/normalizers.test.ts | |
| packages/ui/src/stores/request-locations.test.ts | |
| packages/ui/src/stores/shell-store.test.ts | |
| packages/ui/src/stores/session-generation-recovery.test.ts | |
| packages/ui/src/stores/session-outline-persistence.test.ts | |
| packages/ui/src/stores/session-pagination.test.ts | |
| packages/ui/src/stores/session-fork.test.ts | |
| packages/ui/src/stores/workspace-session-scope.test.ts | |
| packages/ui/src/stores/session-pending-state.test.ts | |
| packages/ui/src/stores/session-tree.test.ts | |
| packages/ui/src/stores/session-previews.test.ts | |
| packages/ui/src/stores/workspace-load-readiness.test.ts | |
| packages/ui/src/types/session.test.ts | |
| packages/ui/src/stores/workspace-list-reconciliation-fence.test.ts | |
| - name: Test restore ownership integration | |
| run: >- | |
| node --conditions=browser --import tsx --test --test-force-exit | |
| packages/ui/src/components/form-request-tool-target.test.ts | |
| packages/ui/src/components/form-request.test.ts | |
| packages/ui/src/components/instance/shell/useSessionCache.test.ts | |
| packages/ui/src/components/permission-diff-review.test.ts | |
| packages/ui/src/components/tool-call/renderers/task-copy.test.ts | |
| packages/ui/src/components/tool-call/renderer-copy.test.ts | |
| packages/ui/src/components/tool-call/diff-payload.test.ts | |
| packages/ui/src/components/tool-call/renderers/edit.test.ts | |
| packages/ui/src/components/tool-call/renderers/task-title.test.ts | |
| packages/ui/src/components/prompt-input/usePromptState.test.ts | |
| packages/ui/src/components/session/provider-usage-panel.test.ts | |
| packages/ui/src/lib/hooks/use-active-session-message-load.test.ts | |
| packages/ui/src/lib/sdk-manager.test.ts | |
| packages/ui/src/lib/background-read-queue.test.ts | |
| packages/ui/src/lib/prioritized-read.test.ts | |
| packages/ui/src/stores/instance-startup-priority.test.ts | |
| packages/ui/src/stores/session-list-startup.test.ts | |
| packages/ui/src/stores/app-tabs.test.ts | |
| packages/ui/src/stores/forms.test.ts | |
| packages/ui/src/stores/preferences-favorites-mode.test.ts | |
| packages/ui/src/stores/instances-restore-ownership.test.ts | |
| packages/ui/src/stores/instances-pending-compaction.test.ts | |
| packages/ui/src/stores/instances-pending-requests.test.ts | |
| packages/ui/src/stores/message-v2/bus.test.ts | |
| packages/ui/src/stores/message-v2/transcript-eviction.test.ts | |
| packages/ui/src/stores/opencode-data.test.ts | |
| packages/ui/src/stores/opencode-data-idle.test.ts | |
| packages/ui/src/stores/opencode-data-settlement.test.ts | |
| packages/ui/src/stores/message-v2/empty-content.test.ts | |
| packages/ui/src/stores/permission-lifecycle.test.ts | |
| packages/ui/src/stores/shell-store-reactivity.test.ts | |
| packages/ui/src/stores/session-actions.test.ts | |
| packages/ui/src/stores/session-model-reconciliation.test.ts | |
| packages/ui/src/stores/session-pruning-events.test.ts | |
| packages/ui/src/stores/session-pruning-projection.test.ts | |
| packages/ui/src/stores/session-pruning-pagination.test.ts | |
| packages/ui/src/stores/session-native-events.test.ts | |
| packages/ui/src/stores/session-outline.test.ts | |
| packages/ui/src/stores/runtime-contract.test.ts | |
| packages/ui/src/stores/session-usage-contract.test.ts | |
| packages/ui/src/stores/session-move-restore.test.ts | |
| packages/ui/src/stores/session-request-authority.test.ts | |
| packages/ui/src/stores/session-git-degraded.test.ts | |
| packages/ui/src/stores/session-send-lifecycle.test.ts | |
| packages/ui/src/stores/blank-session-cleanup.test.ts | |
| packages/ui/src/stores/session-status.test.ts | |
| packages/ui/src/stores/worktree-ready.test.ts | |
| packages/ui/src/stores/worktrees-delete.test.ts | |
| - name: Test server | |
| run: node --import tsx --test "packages/server/src/**/*.test.ts" | |
| - name: Install Chromium for UI rendering regressions | |
| run: npx playwright install --with-deps chromium | |
| - name: Test browser transcript rendering and navigation | |
| run: xvfb-run -a npm run test:browser --workspace @codenomad/ui | |
| - name: Prepare Tauri test resources | |
| run: >- | |
| npm run dev:prep --workspace @codenomad/tauri-app && | |
| node -e "require('fs').mkdirSync('packages/tauri-app/src-tauri/resources/server',{recursive:true})" | |
| - name: Test Tauri crate | |
| working-directory: packages/tauri-app/src-tauri | |
| run: CODENOMAD_TEST_ZSH=/bin/zsh CODENOMAD_TEST_NODE="$(command -v node)" cargo test --locked | |
| - name: Test owned Tauri zoom input script | |
| run: node --test packages/tauri-app/tests/window-zoom-script.test.mjs | |
| tests-tauri-windows: | |
| needs: authorize | |
| if: ${{ needs.authorize.outputs.allowed == 'true' && !github.event.pull_request.draft }} | |
| runs-on: windows-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ github.event.pull_request.head.sha }} | |
| - name: Setup Node | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version-file: .node-version | |
| cache: npm | |
| - name: Setup Rust | |
| uses: dtolnay/rust-toolchain@stable | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Test Windows server spawn behavior | |
| run: node --import tsx --test packages/server/src/workspaces/__tests__/spawn.test.ts | |
| - name: Prepare Tauri test resources | |
| run: >- | |
| npm run dev:prep --workspace @codenomad/tauri-app && | |
| node -e "require('fs').mkdirSync('packages/tauri-app/src-tauri/resources/server',{recursive:true})" | |
| - name: Test Tauri crate on Windows | |
| working-directory: packages/tauri-app/src-tauri | |
| run: cargo test --locked -- --test-threads=1 | |
| - name: Test owned Tauri zoom input script | |
| run: node --test packages/tauri-app/tests/window-zoom-script.test.mjs | |
| - name: Reproduce and prevent Tao input deadlocks | |
| run: node scripts/test-tauri-input-deadlock.mjs --baseline | |
| # Exercise the selected-CLI contract on the reported macOS ARM64 platform as | |
| # well as both other hosts, independently of unrelated server-suite failures. | |
| tests-opencode-compatibility: | |
| needs: authorize | |
| if: ${{ needs.authorize.outputs.allowed == 'true' && !github.event.pull_request.draft }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [ubuntu-latest, windows-latest, macos-26] | |
| runs-on: ${{ matrix.os }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ github.event.pull_request.head.sha }} | |
| - name: Setup Node | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version-file: .node-version | |
| cache: npm | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Test binary compatibility and shared lifecycle | |
| run: >- | |
| node --import tsx --test | |
| packages/server/src/workspaces/__tests__/spawn.test.ts | |
| packages/server/src/workspaces/__tests__/binary-probe.test.ts | |
| packages/server/src/workspaces/session-environment.test.ts | |
| packages/server/src/workspaces/git-requirement.test.ts | |
| packages/server/src/server/__tests__/session-environment.test.ts | |
| "packages/server/src/workspaces/*opencode*.test.ts" | |
| packages/server/src/server/routes/binary-validation.test.ts | |
| "packages/server/src/opencode-update/*.test.ts" | |
| packages/ui/src/lib/launch-errors.test.ts | |
| - name: Test first installation without system Node | |
| timeout-minutes: 10 | |
| run: node scripts/test-opencode-install-native.mjs | |
| - name: Test migration failure guards | |
| run: node --test scripts/native-fixture-guards.test.mjs "scripts/fixtures/wsl-*.test.mjs" | |
| - name: Certify native migration and Git-degraded conversations at the minimum and latest stable | |
| timeout-minutes: 20 | |
| shell: pwsh | |
| run: | | |
| $platform = node -p "process.platform === 'win32' ? 'windows' : process.platform" | |
| $arch = node -p "process.arch" | |
| $extension = node -p "process.platform === 'win32' ? '.exe' : ''" | |
| $seeds = @( | |
| @{ scope = '@opencode'; version = '2.0.3'; command = 'opencode' }, | |
| @{ scope = '@opencode-ai'; version = '0.0.0-beta-19271'; command = 'opencode2' } | |
| ) | |
| $oldClis = foreach ($entry in $seeds) { | |
| $seed = Join-Path $env:RUNNER_TEMP "opencode-migration-seed-$($entry.version)" | |
| npm install --prefix $seed "$($entry.scope)/cli@$($entry.version)" --ignore-scripts --no-audit --no-fund | Out-Host | |
| if ($LASTEXITCODE) { exit $LASTEXITCODE } | |
| Join-Path $seed "node_modules/$($entry.scope)/cli-$platform-$arch/bin/$($entry.command)$extension" | |
| } | |
| $minimum = node --import tsx --input-type=module -e "import { MINIMUM_OPENCODE_VERSION } from './packages/server/src/opencode/runtime-support.ts'; console.log(MINIMUM_OPENCODE_VERSION)" | |
| if ($LASTEXITCODE) { exit $LASTEXITCODE } | |
| foreach ($version in @($minimum, 'latest')) { | |
| $target = Join-Path $env:RUNNER_TEMP "opencode-migration-$version" | |
| npm install --prefix $target "@opencode/cli@$version" --ignore-scripts --no-audit --no-fund | |
| if ($LASTEXITCODE) { exit $LASTEXITCODE } | |
| $cli = Join-Path $target "node_modules/@opencode/cli-$platform-$arch/bin/opencode$extension" | |
| foreach ($oldCli in $oldClis) { | |
| node scripts/test-opencode-history-migration.mjs $oldCli $cli | |
| if ($LASTEXITCODE) { exit $LASTEXITCODE } | |
| } | |
| node scripts/test-git-degraded-native.mjs $cli | |
| if ($LASTEXITCODE) { exit $LASTEXITCODE } | |
| } | |
| # Exercise the window persistence regressions on the architecture reported in | |
| # #676, independently of the Linux server gate. Packaging alone cannot test them. | |
| tests-tauri-macos: | |
| needs: authorize | |
| if: ${{ needs.authorize.outputs.allowed == 'true' && !github.event.pull_request.draft }} | |
| runs-on: macos-26 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ github.event.pull_request.head.sha }} | |
| - name: Setup Node | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version-file: .node-version | |
| cache: npm | |
| - name: Setup Rust | |
| uses: dtolnay/rust-toolchain@stable | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Prepare Tauri test resources | |
| run: >- | |
| npm run dev:prep --workspace @codenomad/tauri-app && | |
| node -e "require('fs').mkdirSync('packages/tauri-app/src-tauri/resources/server',{recursive:true})" | |
| - name: Test Tauri crate on macOS ARM64 | |
| working-directory: packages/tauri-app/src-tauri | |
| run: CODENOMAD_TEST_ZSH=/bin/zsh CODENOMAD_TEST_NODE="$(command -v node)" cargo test --locked -- --test-threads=4 | |
| - name: Reproduce and prevent macOS window event feedback | |
| timeout-minutes: 10 | |
| run: | | |
| node --test scripts/test-tauri-macos-window-result.test.mjs | |
| node scripts/test-tauri-macos-window.mjs --baseline | |
| node scripts/test-tauri-macos-window.mjs --baseline | |
| - name: Test owned Tauri zoom input script | |
| run: node --test packages/tauri-app/tests/window-zoom-script.test.mjs | |
| - name: Test desktop shell startup on macOS | |
| env: | |
| CODENOMAD_TEST_ZSH: /bin/zsh | |
| run: node --import tsx --test packages/electron-app/electron/main/user-shell.test.ts |