mirror of
https://github.com/stablyai/orca.git
synced 2026-10-30 00:27:39 +00:00
Merge #23962's new head into brennanb2025/launch-prompt-argv-carry
Brings #24257's merge of main (e02adc5320) through #23962. Main's refactors met this branch's
carry rule in the startup builders, so the rule now runs inside them:
- Terminal create and agent-session create plan through planExecutionHostLaunchPrompt: main's
OpenCode one-time model preparation, then planLaunchPrompt, with the model's launch config on
whichever plan launches. A draft keeps main's refusal of a model preference.
- The flag-prompt branch uses main's extracted builder (OpenCode run's positional message and
prompt env) with this branch's launch-file directory grant; followupPrompt is gone there too.
- Worktree create keeps main's resolveWorktreeCreateAgentStartup, now awaiting the async builder.
- The relay strips OpenCode's startup-prompt env and probes its plugin before writing the launch
file; the local spawn creates jcode's runtime dir before it.
- Daemon protocol v41 (launch file) keeps main's fish codex-function constant at v39.
- The new-tab launcher keeps main's structured-chat-first route with this branch's launch host.
- Main's new prompted-plan tests (Qoder, Qoder CN, DSH, OpenCode startup prompt and model)
plan through planLaunchPrompt; this branch's new launcher tests carry main's requestId.
- The agent-session startup plan, and the work-item prompt delivery, moved into their own
functions so the merged files stay under the line cap.
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
name: Publish agent state rules
|
||||
|
||||
# The only publisher of agent state rules releases. Merging never publishes: a maintainer runs
|
||||
# this from main, first to `next` (RC and dev builds), then promotes the identical file to
|
||||
# `stable` after a soak. Every job runs on the dispatched commit, so the publish job runs exactly
|
||||
# the script and rules the gate tested.
|
||||
#
|
||||
# Why GITHUB_TOKEN: release-policy.yml deletes an agent-state-rules-* release any other author
|
||||
# publishes. Its releases start no workflow, so release-policy.yml sees them only when someone
|
||||
# edits one by hand, and then accepts them as bot-authored prereleases.
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
action:
|
||||
description: 'publish-next builds from main and publishes to next; promote-stable copies the next file to stable'
|
||||
required: true
|
||||
type: choice
|
||||
options:
|
||||
- publish-next
|
||||
- promote-stable
|
||||
bundled_only:
|
||||
description: 'publish-next: tell apps to fall back to the rules they shipped with; promote-stable then carries it to stable'
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: agent-state-rules-publish
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
gate:
|
||||
if: github.ref == 'refs/heads/main' && inputs.action == 'publish-next'
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: ./.github/actions/install-node-dependencies
|
||||
with:
|
||||
native-runtime: node
|
||||
- name: Run the rules gate (schema, regex safety, the bundle, every transcript replay)
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
mapfile -t gate_files < <(git ls-files \
|
||||
':(glob)src/main/runtime/agent-state-rules/**/*.test.ts' \
|
||||
':(glob)src/main/runtime/readiness-census*.test.ts' \
|
||||
':(glob)src/main/runtime/*transcript.test.ts' \
|
||||
':(glob)src/main/runtime/*transcripts.test.ts' \
|
||||
config/scripts/agent-state-rules-bundle.test.mjs)
|
||||
pnpm exec vitest run --config config/vitest.config.ts "${gate_files[@]}"
|
||||
|
||||
publish-next:
|
||||
needs: gate
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
environment: agent-state-rules
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Publish to next
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
BUNDLED_ONLY: ${{ inputs.bundled_only }}
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
flags=()
|
||||
[[ "$BUNDLED_ONLY" == "true" ]] && flags+=(--bundled-only)
|
||||
node config/scripts/agent-state-rules-bundle.mjs publish-next "${flags[@]}"
|
||||
|
||||
promote-stable:
|
||||
if: github.ref == 'refs/heads/main' && inputs.action == 'promote-stable'
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
environment: agent-state-rules
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Copy the next file to stable
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: node config/scripts/agent-state-rules-bundle.mjs promote-stable
|
||||
@@ -1,16 +1,20 @@
|
||||
name: Warm shared CI caches
|
||||
|
||||
on:
|
||||
# Cache-input pushes seed immediately; this schedule repairs eviction and image changes.
|
||||
schedule:
|
||||
- cron: '41 * * * *'
|
||||
- cron: '41 */6 * * *'
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- '.github/workflows/ci-cache-warmup.yml'
|
||||
- '.github/actions/install-node-dependencies/**'
|
||||
- '.github/actions/restore-pnpm-verification/**'
|
||||
- '.github/actions/prepare-native-runtime/**'
|
||||
- '.github/actions/prepare-git-compatibility/**'
|
||||
- '.github/actions/prepare-headless-compiler/**'
|
||||
- 'config/scripts/headless-detector-compiler-cache*'
|
||||
- '.github/actions/prepare-linux-package-fixture/**'
|
||||
- 'config/docker/headless-serve-shutdown/**'
|
||||
- 'config/docker/cli-launch-contract/**'
|
||||
@@ -33,13 +37,14 @@ on:
|
||||
- 'src/shared/zip-extractor-command.ts'
|
||||
- 'config/scripts/shared-electron-dist-cache.mjs'
|
||||
- 'config/scripts/space-sharing-copy.mjs'
|
||||
- 'config/patches/node-pty@1.1.0.patch'
|
||||
- 'config/patches/@vscode__windows-process-tree@0.8.0.patch'
|
||||
- 'config/patches/**'
|
||||
- 'native/windows-registry/**'
|
||||
pull_request:
|
||||
paths:
|
||||
- '.github/workflows/ci-cache-warmup.yml'
|
||||
- '.github/actions/prepare-git-compatibility/**'
|
||||
- '.github/actions/prepare-headless-compiler/**'
|
||||
- 'config/scripts/headless-detector-compiler-cache*'
|
||||
- '.github/actions/prepare-linux-package-fixture/**'
|
||||
- 'config/docker/headless-serve-shutdown/**'
|
||||
- 'config/docker/cli-launch-contract/**'
|
||||
@@ -51,7 +56,8 @@ permissions:
|
||||
|
||||
concurrency:
|
||||
group: ci-cache-warmup-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
# Scheduled retries must let an active warmer finish publishing its caches.
|
||||
cancel-in-progress: ${{ github.event_name != 'schedule' }}
|
||||
|
||||
jobs:
|
||||
warm:
|
||||
@@ -70,6 +76,11 @@ jobs:
|
||||
native-runtime: node
|
||||
node-version: '24'
|
||||
cache-electron-package: 'true'
|
||||
cache-pnpm-store-lookup-only: 'true'
|
||||
|
||||
- uses: ./.github/actions/prepare-headless-compiler
|
||||
with:
|
||||
seed: 'true'
|
||||
|
||||
- name: Populate shared Electron archive
|
||||
run: node config/scripts/install-electron-package-binary.mjs
|
||||
@@ -103,6 +114,7 @@ jobs:
|
||||
native-runtime: node
|
||||
node-version: '24'
|
||||
cache-electron-package: 'true'
|
||||
cache-pnpm-store-lookup-only: 'true'
|
||||
- name: Populate shared Electron archive
|
||||
run: node config/scripts/install-electron-package-binary.mjs
|
||||
- name: Verify native cache is usable
|
||||
@@ -124,6 +136,7 @@ jobs:
|
||||
- uses: ./.github/actions/install-node-dependencies
|
||||
with:
|
||||
native-runtime: node
|
||||
cache-pnpm-store-lookup-only: 'true'
|
||||
- name: Verify native cache is usable
|
||||
run: node config/scripts/ensure-native-runtime.mjs --check-only
|
||||
|
||||
|
||||
@@ -78,6 +78,7 @@ jobs:
|
||||
production:production-gce-c30) ;;
|
||||
production:production-gce-c31) ;;
|
||||
production:production-gce-c32,production-gce-c33) target_region=us-central1 ;;
|
||||
production:production-gce-c34) ;;
|
||||
*) echo "cell-ids do not match the reviewed environment topology" >&2; exit 1 ;;
|
||||
esac
|
||||
echo "TARGET_REGION=${target_region}" >> "${GITHUB_ENV}"
|
||||
|
||||
@@ -194,7 +194,7 @@ jobs:
|
||||
EXPECTED_REGION=us-central1
|
||||
EXPECTED_DATABASE_POOL_MAX=
|
||||
;;
|
||||
c27|c28|c29|c30|c31)
|
||||
c27|c28|c29|c30|c31|c34)
|
||||
EXPECTED_HARD_CAP=3000
|
||||
EXPECTED_REGION=asia-east2
|
||||
EXPECTED_DATABASE_POOL_MAX=16
|
||||
|
||||
@@ -49,7 +49,7 @@ jobs:
|
||||
# v5 avoids the v6 bootstrap/shim regression when pinning pnpm 10.
|
||||
uses: pnpm/action-setup@v5
|
||||
with:
|
||||
version: 10.24.0
|
||||
version: 10.34.6
|
||||
package_json_file: docs/site/package.json
|
||||
run_install: false
|
||||
|
||||
@@ -224,7 +224,7 @@ jobs:
|
||||
# v5 avoids the v6 bootstrap/shim regression when pinning pnpm 10.
|
||||
uses: pnpm/action-setup@v5
|
||||
with:
|
||||
version: 10.24.0
|
||||
version: 10.34.6
|
||||
package_json_file: docs/site/package.json
|
||||
run_install: false
|
||||
|
||||
|
||||
+21
-14
@@ -119,7 +119,22 @@ jobs:
|
||||
ref: ${{ inputs.ref || github.ref }}
|
||||
|
||||
- name: Install native build tools
|
||||
run: sudo apt-get update && sudo apt-get install -y build-essential python3
|
||||
env:
|
||||
ORCA_E2E_APT_PACKAGES: build-essential python3
|
||||
run: &install_e2e_tools |
|
||||
read -r -a packages <<< "$ORCA_E2E_APT_PACKAGES"
|
||||
for source in /etc/apt/sources.list /etc/apt/sources.list.d/*.list /etc/apt/sources.list.d/*.sources; do
|
||||
if [ -f "$source" ]; then
|
||||
sudo sed -i 's|https*://azure\.archive\.ubuntu\.com/ubuntu|https://archive.ubuntu.com/ubuntu|g' "$source"
|
||||
fi
|
||||
done
|
||||
sudo tee /etc/apt/apt.conf.d/99-orca-e2e >/dev/null <<'APTCONF'
|
||||
Acquire::http::Timeout "15";
|
||||
Acquire::https::Timeout "15";
|
||||
Acquire::Retries "1";
|
||||
APTCONF
|
||||
timeout 120 sudo apt-get update
|
||||
timeout 300 sudo apt-get install -y "${packages[@]}"
|
||||
|
||||
- uses: ./.github/actions/install-node-dependencies
|
||||
with:
|
||||
@@ -178,19 +193,9 @@ jobs:
|
||||
- name: Install native build and headless UI tools
|
||||
# The Azure archive took 16 minutes for one font package; bound setup
|
||||
# separately so a slow mirror cannot consume the shard's test budget.
|
||||
run: &install_e2e_tools |
|
||||
for source in /etc/apt/sources.list /etc/apt/sources.list.d/*.list /etc/apt/sources.list.d/*.sources; do
|
||||
if [ -f "$source" ]; then
|
||||
sudo sed -i 's|https*://azure\.archive\.ubuntu\.com/ubuntu|https://archive.ubuntu.com/ubuntu|g' "$source"
|
||||
fi
|
||||
done
|
||||
sudo tee /etc/apt/apt.conf.d/99-orca-e2e >/dev/null <<'APTCONF'
|
||||
Acquire::http::Timeout "15";
|
||||
Acquire::https::Timeout "15";
|
||||
Acquire::Retries "1";
|
||||
APTCONF
|
||||
timeout 120 sudo apt-get update
|
||||
timeout 300 sudo apt-get install -y build-essential fonts-noto-cjk openssh-client python3 ripgrep xvfb zsh openbox x11-utils
|
||||
env: &e2e_tool_packages
|
||||
ORCA_E2E_APT_PACKAGES: build-essential fonts-noto-cjk openssh-client python3 ripgrep xvfb zsh openbox x11-utils
|
||||
run: *install_e2e_tools
|
||||
|
||||
- uses: ./.github/actions/install-node-dependencies
|
||||
with:
|
||||
@@ -281,6 +286,7 @@ jobs:
|
||||
# unbounded inventory fallback; the paired fixture exercises that real boundary.
|
||||
# Why openssh-client: the Docker-SSH fixture shells out to ssh/ssh-keygen, and this
|
||||
# lane now receives those specs from pr.yml's SSH source mapping.
|
||||
env: *e2e_tool_packages
|
||||
run: *install_e2e_tools
|
||||
|
||||
- uses: ./.github/actions/install-node-dependencies
|
||||
@@ -417,6 +423,7 @@ jobs:
|
||||
ref: ${{ inputs.ref || github.ref }}
|
||||
|
||||
- name: Install native build and headless UI tools
|
||||
env: *e2e_tool_packages
|
||||
run: *install_e2e_tools
|
||||
|
||||
- uses: ./.github/actions/install-node-dependencies
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
name: macOS updater regression tests
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- '.github/workflows/macos-updater-tests.yml'
|
||||
- 'src/main/macos-update-running-instances*'
|
||||
- 'src/main/updater*'
|
||||
- 'src/main/updater/**'
|
||||
- 'src/main/startup/main-process-quit*'
|
||||
- 'src/main/window/main-window-state-lifecycle*'
|
||||
- 'src/main/window/dashboard-popout-window*'
|
||||
- 'src/shared/child-process/**'
|
||||
- 'src/shared/update-status-types.ts'
|
||||
- 'pnpm-lock.yaml'
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: macos-updater-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
updater:
|
||||
runs-on: macos-15
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: ./.github/actions/install-node-dependencies
|
||||
with:
|
||||
native-runtime: node
|
||||
- name: Exercise native application registry and update shutdown
|
||||
env:
|
||||
ORCA_BACKGROUND_LAUNCH: '1'
|
||||
run: >-
|
||||
pnpm exec vitest run --config config/vitest.config.ts
|
||||
src/main/macos-update-running-instances.test.ts
|
||||
src/main/macos-update-running-instances.integration.test.ts
|
||||
src/main/updater.mac-install.test.ts
|
||||
src/main/updater.headless-serve-install.test.ts
|
||||
src/main/updater-mac-quit-guard.test.ts
|
||||
src/main/startup/desktop-startup-ordering.test.ts
|
||||
src/main/startup/main-process-quit-update-veto.test.ts
|
||||
src/main/window/main-window-state-lifecycle.test.ts
|
||||
src/main/window/dashboard-popout-window.test.ts
|
||||
@@ -26,6 +26,7 @@ on:
|
||||
# it or to the release workflow it guards must re-run them.
|
||||
- '.github/workflows/mobile.yml'
|
||||
- '.github/actions/install-node-dependencies/**'
|
||||
- '.github/actions/restore-pnpm-verification/**'
|
||||
- '.github/workflows/mobile-ios-release.yml'
|
||||
- 'config/scripts/mobile-release-check-scope*'
|
||||
- 'config/scripts/mobile-test-change-scope*'
|
||||
@@ -113,18 +114,18 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
# Both compilers are read-only; finish them before starting the test workers.
|
||||
# Call installed tools so pnpm's dependency refresh cannot race between checks.
|
||||
- name: Typecheck
|
||||
id: production-types
|
||||
background: true
|
||||
run: pnpm typecheck
|
||||
run: node node_modules/typescript/bin/tsc --noEmit
|
||||
|
||||
# Why a ratchet and not the raw typecheck: mobile/tsconfig.json excludes test files, so until
|
||||
# tsconfig.test.json existed nothing checked them, and at introduction 127 of the 632 had
|
||||
# drifted. This fails when a test file that checks today stops checking, when a test leaves
|
||||
# the program, and on @ts-nocheck; the baseline may only shrink.
|
||||
- name: Typecheck tests (ratchet)
|
||||
run: pnpm run check:tests-typecheck
|
||||
run: node scripts/check-tests-typecheck-ratchet.mjs
|
||||
|
||||
- wait: production-types
|
||||
|
||||
|
||||
@@ -16,7 +16,10 @@ on:
|
||||
- '.npmrc'
|
||||
- '.pnpmfile.cjs'
|
||||
- '.github/actions/install-node-dependencies/**'
|
||||
- '.github/actions/restore-pnpm-verification/**'
|
||||
- '.github/actions/prepare-headless-compiler/**'
|
||||
- '.github/actions/prepare-native-runtime/**'
|
||||
- '.github/actions/prepare-orcad-prebuilds/**'
|
||||
- '.github/workflows/node-server-tests.yml'
|
||||
# Relevant main pushes qualify every platform after the dependency check.
|
||||
push:
|
||||
@@ -34,7 +37,10 @@ on:
|
||||
- '.npmrc'
|
||||
- '.pnpmfile.cjs'
|
||||
- '.github/actions/install-node-dependencies/**'
|
||||
- '.github/actions/restore-pnpm-verification/**'
|
||||
- '.github/actions/prepare-headless-compiler/**'
|
||||
- '.github/actions/prepare-native-runtime/**'
|
||||
- '.github/actions/prepare-orcad-prebuilds/**'
|
||||
- '.github/workflows/node-server-tests.yml'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
@@ -72,15 +78,18 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
outputs:
|
||||
should_run: ${{ steps.scope.outputs.should_run }}
|
||||
qualification: ${{ steps.scope.outputs.qualification }}
|
||||
runners: ${{ steps.scope.outputs.runners }}
|
||||
should_run: ${{ steps.scope.outputs.should_run || steps.graph.outputs.should_run }}
|
||||
qualification: ${{ steps.scope.outputs.qualification || steps.graph.outputs.qualification }}
|
||||
runners: ${{ steps.scope.outputs.runners || steps.graph.outputs.runners }}
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 2
|
||||
persist-credentials: false
|
||||
- uses: ./.github/actions/install-node-dependencies
|
||||
- uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version-file: package.json
|
||||
package-manager-cache: false
|
||||
- name: Detect headless-server build and test inputs
|
||||
id: scope
|
||||
shell: bash
|
||||
@@ -92,7 +101,7 @@ jobs:
|
||||
# Compare the entire push, including multi-commit pushes and removed files.
|
||||
if git fetch --no-tags --depth=1 origin "$PUSH_BASE" &&
|
||||
git diff --name-only --no-renames -z "$PUSH_BASE" HEAD > "$RUNNER_TEMP/node-server-changes"; then
|
||||
node config/scripts/node-server-change-scope.mjs "$RUNNER_TEMP/node-server-changes" --full-qualification
|
||||
node config/scripts/node-server-change-scope.mjs "$RUNNER_TEMP/node-server-changes" --defer-graph --full-qualification
|
||||
else
|
||||
echo 'should_run=true' >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
@@ -100,11 +109,30 @@ jobs:
|
||||
fi
|
||||
# Compare the tested merge with its base, retaining both sides of renames.
|
||||
if git diff --name-only --no-renames -z HEAD^1 HEAD > "$RUNNER_TEMP/node-server-changes"; then
|
||||
node config/scripts/node-server-change-scope.mjs "$RUNNER_TEMP/node-server-changes"
|
||||
node config/scripts/node-server-change-scope.mjs "$RUNNER_TEMP/node-server-changes" --defer-graph
|
||||
else
|
||||
echo 'should_run=true' >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
- uses: ./.github/actions/prepare-headless-compiler
|
||||
id: compiler
|
||||
if: steps.scope.outputs.graph_required == 'true'
|
||||
continue-on-error: true
|
||||
- uses: ./.github/actions/install-node-dependencies
|
||||
if: steps.scope.outputs.graph_required == 'true' && steps.compiler.outputs.available != 'true'
|
||||
- name: Check the headless import graph
|
||||
id: graph
|
||||
if: steps.scope.outputs.graph_required == 'true'
|
||||
shell: bash
|
||||
env:
|
||||
EVENT_NAME: ${{ github.event_name }}
|
||||
run: |
|
||||
if [ "$EVENT_NAME" = push ]; then
|
||||
node config/scripts/node-server-change-scope.mjs "$RUNNER_TEMP/node-server-changes" --full-qualification
|
||||
else
|
||||
node config/scripts/node-server-change-scope.mjs "$RUNNER_TEMP/node-server-changes"
|
||||
fi
|
||||
|
||||
persistence:
|
||||
needs: changes
|
||||
concurrency:
|
||||
@@ -119,7 +147,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: ${{ fromJSON(needs.changes.outputs.runners || '["ubuntu-22.04","ubuntu-24.04-arm","macos-14","macos-15-intel","windows-2022","windows-11-arm"]') }}
|
||||
os: ${{ fromJSON(needs.changes.outputs.runners || '["ubuntu-22.04","ubuntu-24.04-arm","macos-15","macos-15-intel","windows-2022","windows-11-arm"]') }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
timeout-minutes: 20
|
||||
env:
|
||||
@@ -132,69 +160,44 @@ jobs:
|
||||
- uses: ./.github/actions/install-node-dependencies
|
||||
with:
|
||||
native-runtime: ${{ runner.os == 'Windows' && 'node' || 'none' }}
|
||||
- name: Resolve this Windows server prebuild cache
|
||||
id: orcad-prebuild-cache-identity
|
||||
if: >-
|
||||
runner.os == 'Windows' && (runner.arch == 'X64' || runner.arch == 'ARM64') &&
|
||||
!inputs.build_template && inputs.ref == '' &&
|
||||
(github.event_name == 'pull_request' ||
|
||||
(github.ref == 'refs/heads/main' && contains(fromJSON('["push","schedule","workflow_dispatch"]'), github.event_name)))
|
||||
continue-on-error: true
|
||||
shell: bash
|
||||
run: node config/scripts/orcad-windows-prebuild-cache.mjs --fingerprint
|
||||
- name: Restore the exact Windows server prebuild
|
||||
id: orcad-prebuild-cache-restore
|
||||
if: >-
|
||||
(github.event_name == 'pull_request' || github.event_name == 'push') &&
|
||||
steps.orcad-prebuild-cache-identity.outcome == 'success' &&
|
||||
steps.orcad-prebuild-cache-identity.outputs.key != ''
|
||||
continue-on-error: true
|
||||
uses: actions/cache/restore@v5
|
||||
with:
|
||||
path: ${{ steps.orcad-prebuild-cache-identity.outputs.path }}
|
||||
key: ${{ steps.orcad-prebuild-cache-identity.outputs.key }}
|
||||
# Before setup-node 18: the scripts import the TypeScript runtime pin.
|
||||
# Linux release slots come from the Ubuntu 20.04 and Alpine lanes below, where their libc
|
||||
# floors live; this runner's slot only packages orcad for its own tests.
|
||||
- name: Build and smoke this runner's node-pty prebuild slot under the pinned Node
|
||||
shell: bash
|
||||
env:
|
||||
WINDOWS_PREBUILD_CACHE_HIT: ${{ steps.orcad-prebuild-cache-restore.outputs.cache-hit }}
|
||||
WINDOWS_PREBUILD_CACHE_RESTORE_OUTCOME: ${{ steps.orcad-prebuild-cache-restore.outcome }}
|
||||
run: |
|
||||
if [ "$RUNNER_OS" = Windows ] && [ "$WINDOWS_PREBUILD_CACHE_HIT" = true ] &&
|
||||
[ "$WINDOWS_PREBUILD_CACHE_RESTORE_OUTCOME" = success ] &&
|
||||
node config/scripts/orcad-windows-prebuild-cache.mjs --validate; then
|
||||
echo 'Using the validated Windows server prebuild'
|
||||
else
|
||||
if [ "$RUNNER_OS" = Windows ]; then
|
||||
rm -rf -- out/orcad-prebuilds
|
||||
fi
|
||||
pnpm build:orcad-prebuilds
|
||||
fi
|
||||
pnpm build:orcad-prebuilds --require-slots "$(node config/scripts/build-orcad-prebuilds.mjs --print-slot)"
|
||||
pnpm build:orcad-prebuilds --smoke
|
||||
- run: pnpm build:orcad
|
||||
cache-pnpm-store: ${{ runner.os != 'Windows' }}
|
||||
cache-pnpm-store-lookup-only: 'true'
|
||||
# Design D7 upgrade and rollback: the last Bun orcad, built from a main commit that shipped
|
||||
# it, beside this checkout's Node slot; the live-terminal hand-over skips once PROTOCOL_VERSION
|
||||
# moves past the Bun daemon's. Same lockfile, so its build reuses this checkout's node_modules.
|
||||
# moves past the Bun daemon's. Install its pinned dependencies independently of this checkout.
|
||||
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
|
||||
if: runner.os == 'Linux'
|
||||
with:
|
||||
bun-version: 1.4.2
|
||||
- name: Build the last Bun orcad for the cross-runtime tests
|
||||
if: runner.os == 'Linux'
|
||||
id: bun-orcad
|
||||
background: true
|
||||
shell: bash
|
||||
env:
|
||||
BUN_ORCAD_COMMIT: f4092c06d639ee13ad446261dcabc78b27a21fbc
|
||||
run: |
|
||||
if [ "$RUNNER_OS" != Linux ]; then exit 0; fi
|
||||
git fetch --no-tags --depth=1 origin "$BUN_ORCAD_COMMIT"
|
||||
git worktree add --detach "$RUNNER_TEMP/bun-orcad-source" "$BUN_ORCAD_COMMIT"
|
||||
ln -s "$GITHUB_WORKSPACE/node_modules" "$RUNNER_TEMP/bun-orcad-source/node_modules"
|
||||
pnpm --dir "$RUNNER_TEMP/bun-orcad-source" install --frozen-lockfile --ignore-scripts
|
||||
node "$RUNNER_TEMP/bun-orcad-source/config/scripts/build-orcad-bun.mjs" --out-dir "$RUNNER_TEMP/bun-orcad"
|
||||
echo "ORCA_BUN_ORCAD_SLOT=$RUNNER_TEMP/bun-orcad" >> "$GITHUB_ENV"
|
||||
echo "BUN_EXECUTABLE=$(command -v bun)" >> "$GITHUB_ENV"
|
||||
echo "slot=$RUNNER_TEMP/bun-orcad" >> "$GITHUB_OUTPUT"
|
||||
echo "executable=$(command -v bun)" >> "$GITHUB_OUTPUT"
|
||||
# Linux release slots come from the floor and Alpine lanes; this slot serves local tests.
|
||||
- uses: ./.github/actions/prepare-orcad-prebuilds
|
||||
id: orcad-prebuild
|
||||
with:
|
||||
resolve-windows-cache: >-
|
||||
${{ !inputs.build_template && inputs.ref == '' &&
|
||||
(github.event_name == 'pull_request' ||
|
||||
(github.ref == 'refs/heads/main' && contains(fromJSON('["push","schedule","workflow_dispatch"]'), github.event_name))) }}
|
||||
restore-windows-cache: ${{ github.event_name == 'pull_request' || github.event_name == 'push' }}
|
||||
- run: pnpm build:orcad
|
||||
- wait: bun-orcad
|
||||
- run: pnpm test:node-server --artifact ${{ runner.os == 'Linux' && '--cross-runtime' || '' }}
|
||||
env:
|
||||
ORCA_BUN_ORCAD_SLOT: ${{ steps.bun-orcad.outputs.slot }}
|
||||
BUN_EXECUTABLE: ${{ steps.bun-orcad.outputs.executable }}
|
||||
# Only a Windows runner compiles it; arm64 cross-compiles here, as release-cut does for the relay.
|
||||
# Before the Node 18 check below: the build script imports TypeScript, which Node 18 cannot load.
|
||||
- name: Build the Windows process-table addons for the desktop template
|
||||
@@ -229,13 +232,13 @@ jobs:
|
||||
success() && runner.os == 'Windows' && (runner.arch == 'X64' || runner.arch == 'ARM64') &&
|
||||
!inputs.build_template && inputs.ref == '' && github.ref == 'refs/heads/main' &&
|
||||
contains(fromJSON('["push","schedule","workflow_dispatch"]'), github.event_name) &&
|
||||
steps.orcad-prebuild-cache-identity.outcome == 'success' &&
|
||||
steps.orcad-prebuild-cache-identity.outputs.key != ''
|
||||
steps.orcad-prebuild.outputs.cache-identity-outcome == 'success' &&
|
||||
steps.orcad-prebuild.outputs.cache-key != ''
|
||||
continue-on-error: true
|
||||
uses: actions/cache/save@v5
|
||||
with:
|
||||
path: ${{ steps.orcad-prebuild-cache-identity.outputs.path }}
|
||||
key: ${{ steps.orcad-prebuild-cache-identity.outputs.key }}
|
||||
path: ${{ steps.orcad-prebuild.outputs.cache-path }}
|
||||
key: ${{ steps.orcad-prebuild.outputs.cache-key }}
|
||||
# Linux release slots come from the floor and Alpine lanes; these runners own the rest.
|
||||
- name: Keep this runner's qualified slot for the desktop template
|
||||
if: inputs.build_template && runner.os != 'Linux'
|
||||
@@ -394,11 +397,19 @@ jobs:
|
||||
with:
|
||||
ref: ${{ inputs.ref }}
|
||||
persist-credentials: false
|
||||
- uses: ./.github/actions/restore-pnpm-verification
|
||||
id: pnpm-verification
|
||||
with:
|
||||
container-toolchain: 'true'
|
||||
- name: Verify native Alpine artifact and persistence
|
||||
env:
|
||||
VERIFICATION_CACHE_PATH: ${{ steps.pnpm-verification.outputs.path }}
|
||||
run: |
|
||||
touch "$VERIFICATION_CACHE_PATH"
|
||||
# Multi-arch index digest of the tag; re-resolve it whenever NODE_RUNTIME_PIN moves.
|
||||
docker run --rm --init -i \
|
||||
-e ORCA_BACKGROUND_LAUNCH=1 \
|
||||
-v "$VERIFICATION_CACHE_PATH:/root/.cache/pnpm/lockfile-verified.jsonl" \
|
||||
-v "$GITHUB_WORKSPACE:/work" -w /work \
|
||||
node:24.21.0-alpine@sha256:ebfe2f90462722a7a4de65e91990e97fe0d401c70e0e762c5b53302f905ec1c1 sh -s <<'NODE_SERVER_QUALIFICATION'
|
||||
set -eu
|
||||
|
||||
+149
-62
@@ -154,15 +154,17 @@ jobs:
|
||||
echo "No specs requiring the reusable E2E workflow"
|
||||
fi
|
||||
|
||||
static_analysis:
|
||||
name: static analysis
|
||||
preflight:
|
||||
name: static analysis and typecheck
|
||||
needs: [code_paths]
|
||||
if: needs.code_paths.outputs.static_analysis == 'true'
|
||||
if: needs.code_paths.outputs.static_analysis == 'true' || needs.code_paths.outputs.typecheck == 'true'
|
||||
# Why ARM: measured 128s against 172s on ubuntu-latest, with every compute step faster --
|
||||
# type-aware 24s->15s, anti-slop 28->19s, localization extraction 67->46s, the orcad smoke
|
||||
# 39->14s. Both lint engines ship linux-arm64 and the Bun target follows process.arch, so
|
||||
# the whole toolchain resolves. Free for public repositories, same as the typecheck job.
|
||||
# the whole toolchain resolves. Free for public repositories.
|
||||
runs-on: ubuntu-24.04-arm
|
||||
outputs:
|
||||
shards: ${{ steps.unit-plan.outputs.shards }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
@@ -197,21 +199,35 @@ jobs:
|
||||
|
||||
# Keep each check in its own log while sharing this runner.
|
||||
- name: Lint
|
||||
if: '!cancelled()'
|
||||
id: root-lint
|
||||
background: true
|
||||
run: pnpm exec oxlint --format github
|
||||
env:
|
||||
PREFLIGHT_PHASE_SELECTED: ${{ needs.code_paths.outputs.static_analysis == 'true' }}
|
||||
PREFLIGHT_PRIOR_SUCCESS: ${{ job.status == 'success' }}
|
||||
run: |
|
||||
if [ "$PREFLIGHT_PHASE_SELECTED" != true ] || [ "$PREFLIGHT_PRIOR_SUCCESS" != true ]; then exit 0; fi
|
||||
pnpm exec oxlint --format github
|
||||
|
||||
- name: Reject low-evidence patterns
|
||||
if: needs.code_paths.outputs.static_analysis == 'true'
|
||||
run: pnpm run audit:anti-slop
|
||||
|
||||
- wait: root-lint
|
||||
|
||||
- name: Enforce focused code-quality plugins
|
||||
if: '!cancelled()'
|
||||
id: native-code-quality
|
||||
background: true
|
||||
run: pnpm run audit:code-quality:native
|
||||
env:
|
||||
PREFLIGHT_PHASE_SELECTED: ${{ needs.code_paths.outputs.static_analysis == 'true' }}
|
||||
PREFLIGHT_PRIOR_SUCCESS: ${{ job.status == 'success' }}
|
||||
run: |
|
||||
if [ "$PREFLIGHT_PHASE_SELECTED" != true ] || [ "$PREFLIGHT_PRIOR_SUCCESS" != true ]; then exit 0; fi
|
||||
pnpm run audit:code-quality:native
|
||||
|
||||
- name: Enforce type-aware code-quality baseline
|
||||
if: needs.code_paths.outputs.static_analysis == 'true'
|
||||
run: pnpm run audit:code-quality:type-aware
|
||||
|
||||
# Mobile installation changes import resolution for the native cycle check.
|
||||
@@ -221,28 +237,39 @@ jobs:
|
||||
# resolves types from mobile/node_modules. Without the install every mobile type
|
||||
# degrades to an `error` type — reported as phantom findings against the changed lines.
|
||||
- uses: ./.github/actions/install-mobile-dependencies
|
||||
if: needs.code_paths.outputs.mobile_dependencies == 'true'
|
||||
if: needs.code_paths.outputs.static_analysis == 'true' && needs.code_paths.outputs.mobile_dependencies == 'true'
|
||||
|
||||
- name: Enforce changed-code quality
|
||||
if: '!cancelled()'
|
||||
id: changed-code-quality
|
||||
background: true
|
||||
run: pnpm run check:code-quality:changed -- "${{ github.event.pull_request.base.sha }}"
|
||||
env:
|
||||
PREFLIGHT_PHASE_SELECTED: ${{ needs.code_paths.outputs.static_analysis == 'true' }}
|
||||
PREFLIGHT_PRIOR_SUCCESS: ${{ job.status == 'success' }}
|
||||
run: |
|
||||
if [ "$PREFLIGHT_PHASE_SELECTED" != true ] || [ "$PREFLIGHT_PRIOR_SUCCESS" != true ]; then exit 0; fi
|
||||
pnpm run check:code-quality:changed -- "${{ github.event.pull_request.base.sha }}"
|
||||
|
||||
- name: Enforce React Doctor on changed lines
|
||||
if: needs.code_paths.outputs.static_analysis == 'true'
|
||||
run: pnpm run check:react-doctor:changed -- "${{ github.event.pull_request.base.sha }}"
|
||||
|
||||
- wait: changed-code-quality
|
||||
|
||||
- name: Check Zustand selector fan-out budget
|
||||
if: needs.code_paths.outputs.static_analysis == 'true'
|
||||
run: pnpm run check:zustand-selector-fanout
|
||||
|
||||
- name: Check reliability gate manifest
|
||||
if: needs.code_paths.outputs.static_analysis == 'true'
|
||||
run: pnpm run check:reliability-gates
|
||||
|
||||
- name: Enforce dead design-system classes
|
||||
if: needs.code_paths.outputs.static_analysis == 'true'
|
||||
run: pnpm run check:dead-classes
|
||||
|
||||
- name: Check VM runtime rollback compatibility
|
||||
if: needs.code_paths.outputs.static_analysis == 'true'
|
||||
env:
|
||||
BASE_SHA: ${{ github.event.pull_request.base.sha }}
|
||||
run: |
|
||||
@@ -264,25 +291,33 @@ jobs:
|
||||
config/scripts/ephemeral-vm-runtime-store-cross-version.test.ts
|
||||
|
||||
- name: Enforce max-lines ratchet
|
||||
if: needs.code_paths.outputs.static_analysis == 'true'
|
||||
run: pnpm run check:max-lines-ratchet
|
||||
|
||||
- name: Enforce ts-nocheck ratchet
|
||||
if: needs.code_paths.outputs.static_analysis == 'true'
|
||||
run: pnpm run check:ts-nocheck-ratchet
|
||||
|
||||
- name: Enforce runtime Electron-import ratchet
|
||||
if: needs.code_paths.outputs.static_analysis == 'true'
|
||||
run: pnpm run check:runtime-electron-ratchet
|
||||
|
||||
- name: Check Node runtime pin
|
||||
if: needs.code_paths.outputs.static_analysis == 'true'
|
||||
run: pnpm run check:node-runtime-pin
|
||||
|
||||
# Why: extraction writes sorted evidence to an isolated temporary path,
|
||||
# so feature PRs need one normalized AST pass rather than a three-OS matrix.
|
||||
- name: Verify localization extraction
|
||||
if: '!cancelled()'
|
||||
id: localization-extraction
|
||||
background: true
|
||||
env:
|
||||
PREFLIGHT_PHASE_SELECTED: ${{ needs.code_paths.outputs.static_analysis == 'true' }}
|
||||
PREFLIGHT_PRIOR_SUCCESS: ${{ job.status == 'success' }}
|
||||
BASE_SHA: ${{ github.event.pull_request.base.sha }}
|
||||
run: |
|
||||
if [ "$PREFLIGHT_PHASE_SELECTED" != true ] || [ "$PREFLIGHT_PRIOR_SUCCESS" != true ]; then exit 0; fi
|
||||
# Detection failures run the full check; renames retain the removed input path.
|
||||
DIFF_BASE="$(node config/scripts/git-pull-request-diff-base.mjs "$BASE_SHA")"
|
||||
if git diff --name-only --no-renames -z "$DIFF_BASE" HEAD > "$RUNNER_TEMP/localization-changes" &&
|
||||
@@ -296,6 +331,7 @@ jobs:
|
||||
# which is a property of the import graph. This proves the Node artifact it enables
|
||||
# actually boots, pairs, creates a worktree and round-trips a real PTY.
|
||||
- name: Boot orcad and round-trip a terminal
|
||||
if: needs.code_paths.outputs.static_analysis == 'true'
|
||||
env:
|
||||
BASE_SHA: ${{ github.event.pull_request.base.sha }}
|
||||
ORCA_BACKGROUND_LAUNCH: '1'
|
||||
@@ -310,20 +346,30 @@ jobs:
|
||||
fi
|
||||
|
||||
- name: Verify the generated RPC params catalog
|
||||
if: needs.code_paths.outputs.static_analysis == 'true'
|
||||
run: pnpm run verify:rpc-params-catalog
|
||||
|
||||
- name: Verify bundled skill guides
|
||||
if: needs.code_paths.outputs.static_analysis == 'true'
|
||||
run: pnpm run verify:bundled-skill-guides
|
||||
|
||||
- name: Verify skill freshness manifest
|
||||
if: needs.code_paths.outputs.static_analysis == 'true'
|
||||
run: pnpm run verify:skill-bundle-manifest
|
||||
|
||||
- name: Verify localization catalogs
|
||||
if: '!cancelled()'
|
||||
id: localization-catalogs
|
||||
background: true
|
||||
run: pnpm run verify:localization-catalogs
|
||||
env:
|
||||
PREFLIGHT_PHASE_SELECTED: ${{ needs.code_paths.outputs.static_analysis == 'true' }}
|
||||
PREFLIGHT_PRIOR_SUCCESS: ${{ job.status == 'success' }}
|
||||
run: |
|
||||
if [ "$PREFLIGHT_PHASE_SELECTED" != true ] || [ "$PREFLIGHT_PRIOR_SUCCESS" != true ]; then exit 0; fi
|
||||
pnpm run verify:localization-catalogs
|
||||
|
||||
- name: Verify localization coverage
|
||||
if: needs.code_paths.outputs.static_analysis == 'true'
|
||||
run: pnpm run verify:localization-coverage
|
||||
|
||||
- wait: [localization-catalogs, localization-extraction]
|
||||
@@ -334,6 +380,7 @@ jobs:
|
||||
# in .d.ts to `any`, which is how #1186 shipped a broken IPC signature
|
||||
# past typecheck. See .github/CONTRIBUTING.md#type-declarations-prefer-ts-over-dts.
|
||||
- name: Guard against project-owned .d.ts in preload/shared
|
||||
if: needs.code_paths.outputs.static_analysis == 'true'
|
||||
run: |
|
||||
matches=$(find src/preload src/shared -name '*.d.ts' 2>/dev/null || true)
|
||||
if [ -n "$matches" ]; then
|
||||
@@ -346,33 +393,19 @@ jobs:
|
||||
fi
|
||||
|
||||
- name: Check feature wall asset budget
|
||||
if: needs.code_paths.outputs.static_analysis == 'true'
|
||||
run: pnpm check:feature-wall-assets
|
||||
|
||||
- name: Verify macOS entitlements
|
||||
if: needs.code_paths.outputs.static_analysis == 'true'
|
||||
run: pnpm verify:macos-entitlements
|
||||
|
||||
typecheck:
|
||||
needs: [code_paths]
|
||||
if: needs.code_paths.outputs.typecheck == 'true'
|
||||
# Typechecking uses no native runtime, so it can use the free public ARM runner.
|
||||
runs-on: ubuntu-24.04-arm
|
||||
outputs:
|
||||
shards: ${{ steps.unit-plan.outputs.shards }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 2
|
||||
persist-credentials: false
|
||||
|
||||
- uses: ./.github/actions/install-node-dependencies
|
||||
|
||||
# Why: every project is `composite`, so tsc already writes a .tsbuildinfo that lets
|
||||
# the next run skip unchanged files. Share one cache entry across commits while the
|
||||
# PR base stays stable; actions/cache keeps the first successful graph and the
|
||||
# compiler still invalidates stale files from its content hashes.
|
||||
- name: Cache TypeScript incremental state
|
||||
if: needs.code_paths.outputs.typecheck == 'true'
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: config/*.tsbuildinfo
|
||||
@@ -382,17 +415,24 @@ jobs:
|
||||
|
||||
# Planning shares setup and stays off the compiler's critical path.
|
||||
- name: Plan unit selection
|
||||
if: '!cancelled()'
|
||||
id: unit-plan
|
||||
background: true
|
||||
env:
|
||||
PREFLIGHT_PHASE_SELECTED: ${{ needs.code_paths.outputs.typecheck == 'true' }}
|
||||
PREFLIGHT_PRIOR_SUCCESS: ${{ job.status == 'success' }}
|
||||
ORCA_UNIT_SELECTION_MODE: ${{ vars.ORCA_UNIT_SELECTION_MODE || 'shadow' }}
|
||||
run: node config/scripts/ci-unit-plan.mjs
|
||||
run: |
|
||||
if [ "$PREFLIGHT_PHASE_SELECTED" != true ] || [ "$PREFLIGHT_PRIOR_SUCCESS" != true ]; then exit 0; fi
|
||||
node config/scripts/ci-unit-plan.mjs
|
||||
|
||||
- run: pnpm run typecheck
|
||||
if: needs.code_paths.outputs.typecheck == 'true'
|
||||
|
||||
- wait: unit-plan
|
||||
|
||||
- uses: actions/upload-artifact@v7
|
||||
if: needs.code_paths.outputs.typecheck == 'true'
|
||||
with:
|
||||
name: unit-selection-attempt-${{ github.run_attempt }}
|
||||
path: ci-shards/unit-selection.json
|
||||
@@ -400,8 +440,12 @@ jobs:
|
||||
|
||||
git_compatibility:
|
||||
name: Git compatibility
|
||||
needs: [code_paths]
|
||||
if: needs.code_paths.outputs.git_compatibility == 'true'
|
||||
needs: [code_paths, preflight]
|
||||
if: >-
|
||||
!cancelled() &&
|
||||
needs.code_paths.result == 'success' &&
|
||||
needs.code_paths.outputs.git_compatibility == 'true' &&
|
||||
needs.preflight.result == 'success'
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
@@ -415,6 +459,8 @@ jobs:
|
||||
- uses: ./.github/actions/prepare-git-compatibility
|
||||
|
||||
- name: Verify Git binary compatibility matrix
|
||||
env:
|
||||
ORCA_BACKGROUND_LAUNCH: '1'
|
||||
run: |
|
||||
specs=(
|
||||
"alpine/git:edge-2.38.1|2.38.1"
|
||||
@@ -429,9 +475,13 @@ jobs:
|
||||
pids=()
|
||||
(
|
||||
ORCA_GIT_COMPAT_BINARY="$HOME/.cache/orca-git-compat/git-2.25.5/git" \
|
||||
GIT_EXEC_PATH="$HOME/.cache/orca-git-compat/git-2.25.5" \
|
||||
ORCA_GIT_COMPAT_VERSION="2.25.5" \
|
||||
pnpm exec vitest run --config config/vitest.config.ts \
|
||||
src/shared/git-binary-compatibility.test.ts
|
||||
src/shared/git-binary-compatibility.test.ts \
|
||||
src/main/git/worktree-safety-real-git.test.ts \
|
||||
src/main/git/worktree-rebase-update-refs-real-git.test.ts \
|
||||
src/relay/git-review-draft-binary-compatibility.test.ts
|
||||
) &
|
||||
pids+=("$!")
|
||||
|
||||
@@ -441,7 +491,10 @@ jobs:
|
||||
version="${spec#*|}"
|
||||
ORCA_GIT_COMPAT_IMAGE="$image" ORCA_GIT_COMPAT_VERSION="$version" \
|
||||
pnpm exec vitest run --config config/vitest.config.ts \
|
||||
src/shared/git-binary-compatibility.test.ts
|
||||
src/shared/git-binary-compatibility.test.ts \
|
||||
src/main/git/worktree-safety-real-git.test.ts \
|
||||
src/main/git/worktree-rebase-update-refs-real-git.test.ts \
|
||||
src/relay/git-review-draft-binary-compatibility.test.ts
|
||||
) &
|
||||
pids+=("$!")
|
||||
done
|
||||
@@ -460,8 +513,12 @@ jobs:
|
||||
# repair stops happening. Pinned because the binary is the thing expected to drift.
|
||||
codex_index_heal_contract:
|
||||
name: Codex index-heal contract
|
||||
needs: [code_paths]
|
||||
if: needs.code_paths.outputs.codex_index_heal_contract == 'true'
|
||||
needs: [code_paths, preflight]
|
||||
if: >-
|
||||
!cancelled() &&
|
||||
needs.code_paths.result == 'success' &&
|
||||
needs.code_paths.outputs.codex_index_heal_contract == 'true' &&
|
||||
needs.preflight.result == 'success'
|
||||
# Why ARM: @openai/codex ships @openai/codex-linux-arm64.
|
||||
runs-on: ubuntu-24.04-arm
|
||||
env:
|
||||
@@ -526,8 +583,12 @@ jobs:
|
||||
|
||||
xterm_patch_sync:
|
||||
name: xterm patch sync
|
||||
needs: [code_paths]
|
||||
if: needs.code_paths.outputs.xterm_patch_sync == 'true'
|
||||
needs: [code_paths, preflight]
|
||||
if: >-
|
||||
!cancelled() &&
|
||||
needs.code_paths.result == 'success' &&
|
||||
needs.code_paths.outputs.xterm_patch_sync == 'true' &&
|
||||
needs.preflight.result == 'success'
|
||||
# Why ARM: the patch check rebuilds 4 packages x 2 builds and byte-compares against the
|
||||
# checked-in bundles. Those were generated on Linux x64 and reproduce byte-for-byte on
|
||||
# darwin-arm64, so the output is neither host-arch nor host-OS dependent.
|
||||
@@ -555,8 +616,12 @@ jobs:
|
||||
|
||||
shell_contracts:
|
||||
name: shell contracts
|
||||
needs: [code_paths]
|
||||
if: needs.code_paths.outputs.shell_contracts == 'true'
|
||||
needs: [code_paths, preflight]
|
||||
if: >-
|
||||
!cancelled() &&
|
||||
needs.code_paths.result == 'success' &&
|
||||
needs.code_paths.outputs.shell_contracts == 'true' &&
|
||||
needs.preflight.result == 'success'
|
||||
# Why ARM: fish 4.x is published for noble/arm64 and zsh is in the arm64 archive.
|
||||
runs-on: ubuntu-24.04-arm
|
||||
# Why: this job's cost is almost entirely package download, and a stalled mirror has
|
||||
@@ -671,6 +736,7 @@ jobs:
|
||||
src/main/pty/omp-shell-wrapper.node-pty.test.ts \
|
||||
src/main/fish-xdg-data-dirs-handoff.test.ts \
|
||||
src/main/shell-startup-feature-channel.test.ts \
|
||||
src/main/zsh-deferred-startup-line-init.live-shell.test.ts \
|
||||
src/main/terminal-history-fish-session.node-pty.test.ts \
|
||||
src/main/zsh-scoped-histfile.live-shell.test.ts \
|
||||
src/main/zsh-startup-hook-user-config-equivalence.live-shell.test.ts \
|
||||
@@ -682,35 +748,38 @@ jobs:
|
||||
src/shared/startup-shell-portability.live-shell.test.ts \
|
||||
src/shared/posix-command-path-lookup.test.ts
|
||||
|
||||
# Static analysis saves the Node cache; typecheck publishes the plan before tests fan out.
|
||||
# Preflight saves the Node cache and publishes the plan before tests fan out.
|
||||
test:
|
||||
needs: [code_paths, static_analysis, typecheck]
|
||||
needs: [code_paths, preflight]
|
||||
# Cancellation and failed prerequisites stop the expensive matrix.
|
||||
if: >-
|
||||
!cancelled() &&
|
||||
needs.code_paths.outputs.test == 'true' &&
|
||||
needs.static_analysis.result == 'success' &&
|
||||
needs.typecheck.result == 'success'
|
||||
needs.preflight.result == 'success'
|
||||
uses: ./.github/workflows/unit-tests.yml
|
||||
with:
|
||||
node_versions: '["24"]'
|
||||
runner: ubuntu-24.04-arm
|
||||
shards: ${{ needs.typecheck.outputs.shards }}
|
||||
shards: ${{ needs.preflight.outputs.shards }}
|
||||
|
||||
# Why a sibling and not part of the test workflow: it is advisory, so it must not delay the
|
||||
# gate. Inside unit-tests.yml a caller's `needs: test` waited for it, holding verify ~36s
|
||||
# after the last shard. Deliberately absent from verify's needs for the same reason.
|
||||
unit_selection_evidence:
|
||||
needs: [test]
|
||||
if: ${{ !cancelled() && needs.test.result == 'success' }}
|
||||
if: ${{ !cancelled() && (needs.test.result == 'success' || needs.test.result == 'failure') }}
|
||||
uses: ./.github/workflows/unit-selection-evidence.yml
|
||||
|
||||
# Why a separate job: the test needs a real Chrome, and the sharded `test` matrix
|
||||
# would pay for it on every shard to run one file in whichever shard it landed in.
|
||||
orcad_browser:
|
||||
name: orcad browser provider
|
||||
needs: [code_paths]
|
||||
if: needs.code_paths.outputs.orcad_browser == 'true'
|
||||
needs: [code_paths, preflight]
|
||||
if: >-
|
||||
!cancelled() &&
|
||||
needs.code_paths.result == 'success' &&
|
||||
needs.code_paths.outputs.orcad_browser == 'true' &&
|
||||
needs.preflight.result == 'success'
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
@@ -762,7 +831,7 @@ jobs:
|
||||
# in this job loads node-pty.
|
||||
- uses: ./.github/actions/install-node-dependencies
|
||||
with:
|
||||
native-runtime: node
|
||||
native-runtime: none
|
||||
cache-dependency-path: |
|
||||
pnpm-lock.yaml
|
||||
mobile/pnpm-lock.yaml
|
||||
@@ -823,8 +892,12 @@ jobs:
|
||||
|
||||
cross-version-wire:
|
||||
name: cross-version wire compatibility
|
||||
needs: [code_paths]
|
||||
if: needs.code_paths.outputs.cross-version-wire == 'true'
|
||||
needs: [code_paths, preflight]
|
||||
if: >-
|
||||
!cancelled() &&
|
||||
needs.code_paths.result == 'success' &&
|
||||
needs.code_paths.outputs.cross-version-wire == 'true' &&
|
||||
needs.preflight.result == 'success'
|
||||
# Why ARM: source-only: tagged checkout plus in-process vitest, no docker or browser.
|
||||
runs-on: ubuntu-24.04-arm
|
||||
|
||||
@@ -867,8 +940,12 @@ jobs:
|
||||
|
||||
managed_hook_node18:
|
||||
name: managed hooks on Node 18
|
||||
needs: [code_paths]
|
||||
if: needs.code_paths.outputs.managed_hook_node18 == 'true'
|
||||
needs: [code_paths, preflight]
|
||||
if: >-
|
||||
!cancelled() &&
|
||||
needs.code_paths.result == 'success' &&
|
||||
needs.code_paths.outputs.managed_hook_node18 == 'true' &&
|
||||
needs.preflight.result == 'success'
|
||||
# Why ARM: Node 18 publishes linux-arm64; the per-platform runtime files are read as data.
|
||||
runs-on: ubuntu-24.04-arm
|
||||
|
||||
@@ -893,7 +970,7 @@ jobs:
|
||||
|
||||
package:
|
||||
name: package
|
||||
needs: [code_paths, static_analysis, typecheck]
|
||||
needs: [code_paths, preflight]
|
||||
if: needs.code_paths.outputs.package == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
# Let the serial Docker gates reach their own deadlines and report cleanup failures.
|
||||
@@ -1050,7 +1127,7 @@ jobs:
|
||||
|
||||
package_windows:
|
||||
name: package (windows)
|
||||
needs: [code_paths, static_analysis, typecheck]
|
||||
needs: [code_paths, preflight]
|
||||
if: needs.code_paths.outputs.package_windows == 'true'
|
||||
runs-on: windows-2022
|
||||
timeout-minutes: 30
|
||||
@@ -1129,6 +1206,7 @@ jobs:
|
||||
src/shared/child-process/windows-cmd-shim-resolution.test.ts
|
||||
src/shared/child-process/windows-cmd-shim-resolution.win32.test.ts
|
||||
src/main/agent-hooks/windows-hook-payload-delivery.test.ts
|
||||
src/main/jcode/hook-gate-script.test.ts
|
||||
src/main/agent-hooks/windows-direct-cmd-hook-command.test.ts
|
||||
src/main/codex/windows-hook-command.test.ts
|
||||
src/main/codex/windows-hook-upgrade.test.ts
|
||||
@@ -1159,6 +1237,8 @@ jobs:
|
||||
src/main/runtime/unreadable-secret-store-preservation.win32.test.ts
|
||||
src/main/ipc/pty-codex-account-attribution.test.ts
|
||||
src/main/ipc/pty-spawn-env-codex-resume-provenance.test.ts
|
||||
src/main/ipc/preflight-provider-command-selection.test.ts
|
||||
src/main/ipc/preflight-runnable-local-cli.test.ts
|
||||
src/relay/windows-port-scan.win32.test.ts
|
||||
src/main/ssh/ssh-relay-upload-stage-windows-identity.test.ts
|
||||
src/main/ssh/remote-node-runtime-store-windows.test.ts
|
||||
@@ -1212,8 +1292,19 @@ jobs:
|
||||
|
||||
e2e:
|
||||
name: e2e
|
||||
needs: code_paths
|
||||
if: needs.code_paths.outputs.e2e_should_run == 'true'
|
||||
needs: [code_paths, preflight]
|
||||
if: >-
|
||||
!cancelled() &&
|
||||
needs.code_paths.result == 'success' &&
|
||||
needs.code_paths.outputs.e2e_should_run == 'true' &&
|
||||
(
|
||||
needs.preflight.result == 'success' ||
|
||||
(
|
||||
needs.preflight.result == 'skipped' &&
|
||||
needs.code_paths.outputs.static_analysis == 'false' &&
|
||||
needs.code_paths.outputs.typecheck == 'false'
|
||||
)
|
||||
)
|
||||
# Why: reusable e2e.yml only checkouts, builds, and uploads artifacts.
|
||||
permissions:
|
||||
contents: read
|
||||
@@ -1256,8 +1347,7 @@ jobs:
|
||||
if: ${{ !cancelled() }}
|
||||
needs:
|
||||
- code_paths
|
||||
- static_analysis
|
||||
- typecheck
|
||||
- preflight
|
||||
- git_compatibility
|
||||
- codex_index_heal_contract
|
||||
- xterm_patch_sync
|
||||
@@ -1286,10 +1376,8 @@ jobs:
|
||||
env:
|
||||
CODE_PATHS: ${{ needs.code_paths.result }}
|
||||
SHOULD_RUN: ${{ needs.code_paths.outputs.should_run }}
|
||||
STATIC_ANALYSIS: ${{ needs.static_analysis.result }}
|
||||
STATIC_ANALYSIS_SHOULD_RUN: ${{ needs.code_paths.outputs.static_analysis }}
|
||||
TYPECHECK: ${{ needs.typecheck.result }}
|
||||
TYPECHECK_SHOULD_RUN: ${{ needs.code_paths.outputs.typecheck }}
|
||||
PREFLIGHT: ${{ needs.preflight.result }}
|
||||
PREFLIGHT_SHOULD_RUN: ${{ needs.code_paths.outputs.static_analysis == 'true' || needs.code_paths.outputs.typecheck == 'true' }}
|
||||
GIT_COMPATIBILITY: ${{ needs.git_compatibility.result }}
|
||||
GIT_COMPATIBILITY_SHOULD_RUN: ${{ needs.code_paths.outputs.git_compatibility }}
|
||||
CODEX_INDEX_HEAL_CONTRACT: ${{ needs.codex_index_heal_contract.result }}
|
||||
@@ -1335,8 +1423,7 @@ jobs:
|
||||
fi
|
||||
}
|
||||
# Require success when the PR has code-relevant changes
|
||||
check_job static_analysis "$STATIC_ANALYSIS" "$STATIC_ANALYSIS_SHOULD_RUN"
|
||||
check_job typecheck "$TYPECHECK" "$TYPECHECK_SHOULD_RUN"
|
||||
check_job preflight "$PREFLIGHT" "$PREFLIGHT_SHOULD_RUN"
|
||||
check_job git_compatibility "$GIT_COMPATIBILITY" "$GIT_COMPATIBILITY_SHOULD_RUN"
|
||||
check_job codex_index_heal_contract "$CODEX_INDEX_HEAL_CONTRACT" "$CODEX_INDEX_HEAL_CONTRACT_SHOULD_RUN"
|
||||
check_job xterm_patch_sync "$XTERM_PATCH_SYNC" "$XTERM_PATCH_SYNC_SHOULD_RUN"
|
||||
|
||||
@@ -79,6 +79,7 @@ jobs:
|
||||
source_ref: ${{ steps.resolve.outputs.ref }}
|
||||
source_sha: ${{ steps.resolve.outputs.sha }}
|
||||
source_short_sha: ${{ steps.resolve.outputs.short_sha }}
|
||||
ships_orcad_template: ${{ steps.orcad-template-support.outputs.ships }}
|
||||
steps:
|
||||
# Why inlined (not m-s-abeer/update-gha-summary-with-workflow-inputs):
|
||||
# this job runs with contents:write and secret scope, so avoid executing
|
||||
@@ -783,6 +784,21 @@ jobs:
|
||||
git push origin "$TAG"
|
||||
fi
|
||||
|
||||
# Why: a patch cut from a base older than #24155 has no orcad template to build or ship.
|
||||
- name: Detect whether the tag ships the orcad template
|
||||
id: orcad-template-support
|
||||
if: steps.tag.outputs.tag != '' || steps.version.outputs.recovered_tag != ''
|
||||
env:
|
||||
TAG: ${{ steps.tag.outputs.tag || steps.version.outputs.recovered_tag }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
if git cat-file -e "refs/tags/${TAG}^{commit}:config/scripts/packaged-orcad-template.cjs" 2>/dev/null; then
|
||||
echo "ships=true" >>"$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "ships=false" >>"$GITHUB_OUTPUT"
|
||||
echo "::notice::$TAG predates the orcad template; skipping its build and download."
|
||||
fi
|
||||
|
||||
- name: Release E2E signal summary
|
||||
if: always()
|
||||
run: |
|
||||
@@ -1154,7 +1170,7 @@ jobs:
|
||||
# signing quota, so it runs beside the release gates instead of behind them.
|
||||
orcad-template:
|
||||
needs: cut
|
||||
if: needs.cut.outputs.should_release == 'true'
|
||||
if: needs.cut.outputs.should_release == 'true' && needs.cut.outputs.ships_orcad_template == 'true'
|
||||
permissions:
|
||||
contents: read
|
||||
uses: ./.github/workflows/node-server-tests.yml
|
||||
@@ -1203,7 +1219,16 @@ jobs:
|
||||
- orcad-template
|
||||
- release-preflight
|
||||
- relay-windows-process-tree
|
||||
if: needs.cut.outputs.should_release == 'true'
|
||||
# Why not the implicit success(): a tag without the orcad template skips that job on purpose.
|
||||
if: >-
|
||||
!cancelled() &&
|
||||
needs.cut.result == 'success' &&
|
||||
needs.cut.outputs.should_release == 'true' &&
|
||||
needs.create-release.result == 'success' &&
|
||||
needs.release-preflight.result == 'success' &&
|
||||
needs.relay-windows-process-tree.result == 'success' &&
|
||||
(needs.orcad-template.result == 'success' ||
|
||||
(needs.orcad-template.result == 'skipped' && needs.cut.outputs.ships_orcad_template == 'false'))
|
||||
env:
|
||||
# beforePack and afterPack fail the package when the template is absent.
|
||||
ORCA_REQUIRE_ORCAD_TEMPLATE: '1'
|
||||
@@ -1463,6 +1488,7 @@ jobs:
|
||||
|
||||
# After the app build so nothing that cleans out/ can drop it; electron-builder ships it.
|
||||
- name: Download the orcad deployment template
|
||||
if: needs.cut.outputs.ships_orcad_template == 'true'
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: orcad-template
|
||||
@@ -1806,7 +1832,7 @@ jobs:
|
||||
# each file against the template manifest, so it must record the signed bytes.
|
||||
- name: Reseal the orcad template over its signed binaries
|
||||
id: reseal-orcad-template
|
||||
if: matrix.platform == 'win' && github.run_attempt == 1 && steps.restore-signed-inner.outcome == 'success'
|
||||
if: matrix.platform == 'win' && github.run_attempt == 1 && steps.restore-signed-inner.outcome == 'success' && needs.cut.outputs.ships_orcad_template == 'true'
|
||||
run: node config/scripts/packaged-orcad-template.cjs --reseal-signed dist/win-unpacked inner-signing-list.txt
|
||||
|
||||
# The uninstaller must return signed before rebuilding the installer.
|
||||
@@ -2306,7 +2332,16 @@ jobs:
|
||||
- release-preflight
|
||||
# release-mac-build.yml downloads the relay addons from this run.
|
||||
- relay-windows-process-tree
|
||||
if: needs.cut.outputs.should_release == 'true'
|
||||
# Why not the implicit success(): a tag without the orcad template skips that job on purpose.
|
||||
if: >-
|
||||
!cancelled() &&
|
||||
needs.cut.result == 'success' &&
|
||||
needs.cut.outputs.should_release == 'true' &&
|
||||
needs.create-release.result == 'success' &&
|
||||
needs.release-preflight.result == 'success' &&
|
||||
needs.relay-windows-process-tree.result == 'success' &&
|
||||
(needs.orcad-template.result == 'success' ||
|
||||
(needs.orcad-template.result == 'skipped' && needs.cut.outputs.ships_orcad_template == 'false'))
|
||||
# Why: SignPath requires every job in this signing workflow to be
|
||||
# GitHub-hosted. The actual mac build runs in release-mac-build.yml so
|
||||
# Blacksmith stays outside Windows artifact provenance.
|
||||
@@ -2340,6 +2375,15 @@ jobs:
|
||||
- skill-sharing-linux-floor-release-gate
|
||||
- skill-sharing-release-gate
|
||||
- terminal-rendering-golden
|
||||
# Why explicit: a skipped orcad-template (tags that predate it) would skip every job after it.
|
||||
if: >-
|
||||
!cancelled() &&
|
||||
needs.cut.result == 'success' &&
|
||||
needs.build.result == 'success' &&
|
||||
needs.build-mac.result == 'success' &&
|
||||
needs.skill-sharing-linux-floor-release-gate.result == 'success' &&
|
||||
needs.skill-sharing-release-gate.result == 'success' &&
|
||||
needs.terminal-rendering-golden.result == 'success'
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
@@ -2408,7 +2452,8 @@ jobs:
|
||||
needs:
|
||||
- cut
|
||||
- publish-release
|
||||
if: ${{ needs.cut.outputs.tag != '' }}
|
||||
# Why explicit: a skipped orcad-template (tags that predate it) would skip every job after it.
|
||||
if: ${{ !cancelled() && needs.publish-release.result == 'success' && needs.cut.outputs.tag != '' }}
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: write
|
||||
@@ -2437,7 +2482,8 @@ jobs:
|
||||
# A release created with GITHUB_TOKEN does not reliably emit a release
|
||||
# event to other workflows. Dispatch the trusted default-branch workflow;
|
||||
# it validates and checks out the released tag before deploying.
|
||||
if: ${{ needs.cut.outputs.tag != '' }}
|
||||
# Why explicit: a skipped orcad-template (tags that predate it) would skip every job after it.
|
||||
if: ${{ !cancelled() && needs.publish-release.result == 'success' && needs.cut.outputs.tag != '' }}
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: write
|
||||
@@ -2481,7 +2527,8 @@ jobs:
|
||||
needs:
|
||||
- cut
|
||||
- publish-release
|
||||
if: ${{ needs.cut.outputs.tag != '' && startsWith(needs.cut.outputs.tag, 'v') }}
|
||||
# Why explicit: a skipped orcad-template (tags that predate it) would skip every job after it.
|
||||
if: ${{ !cancelled() && needs.publish-release.result == 'success' && needs.cut.outputs.tag != '' && startsWith(needs.cut.outputs.tag, 'v') }}
|
||||
uses: ./.github/workflows/homebrew-bump.yml
|
||||
with:
|
||||
tag: ${{ needs.cut.outputs.tag }}
|
||||
|
||||
@@ -158,6 +158,8 @@ jobs:
|
||||
|
||||
# Design D2: the parent release-cut run merged it from every node-server lane at this tag.
|
||||
- name: Download the orcad deployment template from the release run
|
||||
# Why: release-cut skips the template for a tag that predates it.
|
||||
if: hashFiles('config/scripts/packaged-orcad-template.cjs') != ''
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: orcad-template
|
||||
|
||||
@@ -22,7 +22,9 @@ jobs:
|
||||
# Why: release events run this file from the tagged commit, so load the module from the same commit.
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
sparse-checkout: config/scripts/release-policy.mjs
|
||||
sparse-checkout: |
|
||||
config/scripts/release-policy.mjs
|
||||
config/scripts/release-tag-patterns.mjs
|
||||
sparse-checkout-cone-mode: false
|
||||
persist-credentials: false
|
||||
- name: Enforce release policy
|
||||
|
||||
@@ -27,6 +27,7 @@ on:
|
||||
- '!src/**/*.test.ts'
|
||||
- 'src/main/ssh/ssh-relay-hostile-hosts.docker.test.ts'
|
||||
- '.github/workflows/ssh-hostile-hosts.yml'
|
||||
- '.github/actions/restore-pnpm-verification/**'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
cells:
|
||||
@@ -56,7 +57,17 @@ jobs:
|
||||
PYTHON: /opt/python/cp312-cp312/bin/python3
|
||||
steps:
|
||||
- name: Install glibc 2.28 prerequisites
|
||||
run: dnf install -y git procps-ng unzip which xz
|
||||
run: |
|
||||
missing_tool=false
|
||||
for tool in git ps unzip which xz; do
|
||||
if ! command -v "$tool" >/dev/null 2>&1; then
|
||||
missing_tool=true
|
||||
fi
|
||||
done
|
||||
if [ "$missing_tool" = true ]; then
|
||||
# The image's source-built Git needs no RPM; missing tools come from AlmaLinux.
|
||||
dnf --disablerepo='epel*' install -y git procps-ng unzip which xz
|
||||
fi
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
@@ -89,11 +100,19 @@ jobs:
|
||||
with:
|
||||
name: hostile-hosts-glibc-slot
|
||||
path: out/orcad-prebuilds
|
||||
- uses: ./.github/actions/restore-pnpm-verification
|
||||
id: pnpm-verification
|
||||
with:
|
||||
container-toolchain: 'true'
|
||||
- name: Build and smoke the linux-x64-musl slot on Alpine
|
||||
env:
|
||||
VERIFICATION_CACHE_PATH: ${{ steps.pnpm-verification.outputs.path }}
|
||||
run: |
|
||||
touch "$VERIFICATION_CACHE_PATH"
|
||||
# Same digest as the headless-server musl lane; re-resolve it whenever NODE_RUNTIME_PIN moves.
|
||||
docker run --rm --init -i \
|
||||
-e ORCA_BACKGROUND_LAUNCH=1 \
|
||||
-v "$VERIFICATION_CACHE_PATH:/root/.cache/pnpm/lockfile-verified.jsonl" \
|
||||
-v "$GITHUB_WORKSPACE:/work" -w /work \
|
||||
node:24.21.0-alpine@sha256:ebfe2f90462722a7a4de65e91990e97fe0d401c70e0e762c5b53302f905ec1c1 sh -s <<'MUSL_SLOT'
|
||||
set -eu
|
||||
@@ -198,7 +217,7 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: macos-14
|
||||
- os: macos-15
|
||||
target: darwin-arm64
|
||||
cell: macos-arm64-local-sshd
|
||||
- os: macos-15-intel
|
||||
|
||||
@@ -28,12 +28,16 @@ on:
|
||||
- 'config/patches/@vscode__windows-process-tree*'
|
||||
- 'config/scripts/build-windows-process-tree-relay-addon.mjs'
|
||||
- 'config/scripts/relay-windows-process-tree-staging.mjs'
|
||||
- 'config/scripts/relay-windows-process-tree-prepared-addon*.mjs'
|
||||
- 'config/scripts/windows-process-tree-gyp-rebuild.mjs'
|
||||
- 'src/shared/relay-windows-breakaway-launch.ts'
|
||||
- '!src/**/*.test.ts'
|
||||
- 'src/main/ssh/ssh-relay-windows-host-lane.test.ts'
|
||||
- 'config/ci/windows-ssh-provider/**'
|
||||
- '.github/workflows/ssh-windows-hosts.yml'
|
||||
- '.github/actions/prepare-orcad-prebuilds/**'
|
||||
- '.github/actions/restore-pnpm-verification/**'
|
||||
- 'config/scripts/orcad-windows-prebuild-cache.mjs'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
cells:
|
||||
@@ -80,9 +84,17 @@ jobs:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: ./.github/actions/install-node-dependencies
|
||||
with:
|
||||
native-runtime: node
|
||||
# Keep complete server/test trees; missing future imports fail the unchanged builds.
|
||||
sparse-checkout: |
|
||||
.github
|
||||
config
|
||||
native
|
||||
resources
|
||||
tests
|
||||
src/main
|
||||
src/shared
|
||||
src/relay
|
||||
src/types
|
||||
- name: Self-test the provisioning scripts before touching the machine
|
||||
shell: pwsh
|
||||
run: |
|
||||
@@ -92,20 +104,49 @@ jobs:
|
||||
if($errors.Count){throw "PowerShell parse failed: $($file.FullName)"}
|
||||
}
|
||||
& config/ci/windows-ssh-provider/preview-ssh/test-preview-diagnostics.ps1
|
||||
# ARM inbox servicing can finish while the independent Node artifacts are prepared.
|
||||
- name: Prepare the Windows inbox SSH capability
|
||||
id: inbox-capability
|
||||
background: true
|
||||
shell: pwsh
|
||||
run: |
|
||||
if('${{ matrix.server }}' -eq 'inbox' -and '${{ matrix.arch }}' -eq 'arm64'){
|
||||
$receipts=Join-Path $pwd '.build/ssh-windows-host-receipts'
|
||||
New-Item -ItemType Directory -Force -Path $receipts | Out-Null
|
||||
. config/ci/windows-ssh-provider/preview-ssh/windows-ssh-capability.ps1
|
||||
Initialize-WindowsInboxSshCapability -Arch '${{ matrix.arch }}' -Receipt (Join-Path $receipts 'inbox-capability-preparation.json')
|
||||
}
|
||||
- uses: ./.github/actions/install-node-dependencies
|
||||
id: dependencies
|
||||
with:
|
||||
native-runtime: node
|
||||
cache-pnpm-store: 'false'
|
||||
# The deploy materializes rung A from this template; only this runner's slot exists here.
|
||||
# The process-tree addon carries the launcher that starts the relay outside sshd's job; the
|
||||
# orcad slot and the relay both stage it, and a standard-user host has no other launch route.
|
||||
- name: Build this runner's orcad slot, the win32 template and the relay
|
||||
- name: Build this runner's Windows process-table addon
|
||||
shell: bash
|
||||
env:
|
||||
REUSE_PREPARED_RUNTIME: ${{ github.event_name == 'pull_request' && steps.dependencies.outputs.native-cache-hit == 'true' }}
|
||||
run: |
|
||||
reuse_args=()
|
||||
if [ "$REUSE_PREPARED_RUNTIME" = true ]; then
|
||||
reuse_args+=(--reuse-prepared-runtime)
|
||||
fi
|
||||
node config/scripts/build-windows-process-tree-relay-addon.mjs --arch=${{ matrix.arch }} "${reuse_args[@]}"
|
||||
- uses: ./.github/actions/prepare-orcad-prebuilds
|
||||
with:
|
||||
resolve-windows-cache: ${{ github.event_name == 'pull_request' }}
|
||||
restore-windows-cache: ${{ github.event_name == 'pull_request' }}
|
||||
- name: Build the win32 template and the relay
|
||||
shell: bash
|
||||
env:
|
||||
ORCA_REQUIRE_RELAY_NATIVE_ADDONS: ${{ matrix.arch }}
|
||||
run: |
|
||||
node config/scripts/build-windows-process-tree-relay-addon.mjs --arch=${{ matrix.arch }}
|
||||
pnpm build:orcad-prebuilds
|
||||
pnpm build:orcad-prebuilds --require-slots "win32-${{ matrix.arch }}"
|
||||
pnpm build:orcad-prebuilds --smoke
|
||||
node config/scripts/build-orcad-template.mjs --targets "win32-${{ matrix.arch }}"
|
||||
pnpm run build:relay
|
||||
- wait: inbox-capability
|
||||
- name: Run the Windows host cells against a private ${{ matrix.server }} sshd
|
||||
shell: pwsh
|
||||
timeout-minutes: 50
|
||||
@@ -119,6 +160,8 @@ jobs:
|
||||
$cells=@($env:CELLS -split ',' | ForEach-Object {$_.Trim()} | Where-Object {$_})
|
||||
if(-not $cells.Count){$cells=@('pinned-cmd','pinned-powershell','legacy-opt-out')}
|
||||
$archive=''
|
||||
$preparation=''
|
||||
if('${{ matrix.server }}' -eq 'inbox' -and '${{ matrix.arch }}' -eq 'arm64'){$preparation=Join-Path $receipts 'inbox-capability-preparation.json'}
|
||||
if('${{ matrix.server }}' -eq 'preview'){
|
||||
$archive=Join-Path $env:RUNNER_TEMP 'preview-${{ matrix.archive }}'
|
||||
# The provisioning script refuses the archive unless its sha256 and every binary's match the pin.
|
||||
@@ -128,7 +171,7 @@ jobs:
|
||||
$callback={param($context)
|
||||
& (Join-Path $tools 'invoke-pinned-relay-cells.ps1') -SourceRoot $sourceRoot -Context $context -Target 'win32-${{ matrix.arch }}' -ReceiptRoot $receipts -Cells $cells
|
||||
}.GetNewClosure()
|
||||
& (Join-Path $tools 'preview-ssh/prove-preview-openssh.ps1') -Archive $archive -Arch '${{ matrix.arch }}' -Server '${{ matrix.server }}' -Receipt (Join-Path $receipts 'provider-server.json') -Accounts $cells.Count -HiddenTools @('npm','npx','node-gyp','gcc','g++','cc','c++','make','cl','clang','clang++','msbuild','cmake') -HostCellProbe $callback 2>&1 | Tee-Object (Join-Path $receipts 'provision.log')
|
||||
& (Join-Path $tools 'preview-ssh/prove-preview-openssh.ps1') -Archive $archive -Arch '${{ matrix.arch }}' -Server '${{ matrix.server }}' -Receipt (Join-Path $receipts 'provider-server.json') -InboxPreparationReceipt $preparation -Accounts $cells.Count -HiddenTools @('npm','npx','node-gyp','gcc','g++','cc','c++','make','cl','clang','clang++','msbuild','cmake') -HostCellProbe $callback 2>&1 | Tee-Object (Join-Path $receipts 'provision.log')
|
||||
- uses: actions/upload-artifact@v7
|
||||
if: always()
|
||||
with:
|
||||
|
||||
@@ -5,12 +5,21 @@ on:
|
||||
# change is worth a real ibus session. A pull_request trigger here would run it on every PR.
|
||||
workflow_call:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
diagnose_wayland_input:
|
||||
description: Capture passive Wayland input diagnostics while running both native lanes
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
schedule:
|
||||
- cron: '30 9 * * *'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
env:
|
||||
ORCA_BACKGROUND_LAUNCH: '1'
|
||||
|
||||
jobs:
|
||||
linux-x11:
|
||||
name: Linux X11 terminal IME
|
||||
@@ -98,6 +107,7 @@ jobs:
|
||||
- name: Run native Wayland Hangul terminating digit
|
||||
env:
|
||||
SKIP_BUILD: '1'
|
||||
ORCA_E2E_WAYLAND_INPUT_DIAGNOSTICS: ${{ inputs.diagnose_wayland_input && '1' || '' }}
|
||||
run: node config/scripts/run-terminal-ibus-hangul-e2e.mjs --nested-wayland
|
||||
- name: Upload Wayland terminal IME evidence
|
||||
if: always()
|
||||
|
||||
@@ -68,25 +68,60 @@ jobs:
|
||||
- name: Install native build tools and xvfb
|
||||
run: sudo apt-get update && sudo apt-get install -y build-essential python3 xvfb zsh
|
||||
|
||||
- name: Select dependency preparation
|
||||
id: install-mode
|
||||
shell: bash
|
||||
env:
|
||||
RUNNER_KIND: ${{ runner.environment }}
|
||||
JOB_CONTAINER: ${{ job.container.id }}
|
||||
run: |
|
||||
node <<'NODE'
|
||||
const fs = require('node:fs')
|
||||
const manifest = JSON.parse(fs.readFileSync('package.json', 'utf8'))
|
||||
const actionPath = '.github/actions/install-node-dependencies/action.yml'
|
||||
const action = fs.existsSync(actionPath) ? fs.readFileSync(actionPath, 'utf8') : ''
|
||||
const inputs = action.split(/^inputs:[ \t]*\r?$/m)[1]?.split(/^\S/m)[0] ?? ''
|
||||
const shared = process.env.RUNNER_KIND === 'github-hosted' && !process.env.JOB_CONTAINER &&
|
||||
process.env.RUNNER_OS === 'Linux' && process.env.RUNNER_ARCH === 'X64' &&
|
||||
manifest.engines?.node === '24' && typeof manifest.packageManager === 'string' &&
|
||||
manifest.packageManager.split('+')[0] === 'pnpm@12.8.1' &&
|
||||
manifest.scripts?.postinstall === 'node config/scripts/rebuild-native-deps.mjs' &&
|
||||
/^ native-runtime:/m.test(inputs) && /^ cache-pnpm-store-lookup-only:/m.test(inputs) &&
|
||||
fs.existsSync('.github/actions/prepare-native-runtime/action.yml') &&
|
||||
fs.existsSync('config/scripts/ensure-native-runtime.mjs')
|
||||
fs.appendFileSync(process.env.GITHUB_OUTPUT, `shared=${shared}\n`)
|
||||
NODE
|
||||
|
||||
- name: Prepare current dependencies
|
||||
if: steps.install-mode.outputs.shared == 'true'
|
||||
uses: ./.github/actions/install-node-dependencies
|
||||
with:
|
||||
native-runtime: electron
|
||||
cache-electron-package: 'true'
|
||||
cache-pnpm-store-lookup-only: 'true'
|
||||
|
||||
- name: Setup pnpm
|
||||
if: steps.install-mode.outputs.shared != 'true'
|
||||
uses: pnpm/setup@v2
|
||||
with:
|
||||
install: false
|
||||
|
||||
- name: Setup Node.js
|
||||
if: steps.install-mode.outputs.shared != 'true'
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version-file: package.json
|
||||
cache: pnpm
|
||||
|
||||
# Why: this scheduled/manual workflow uses the same native install path as
|
||||
# PR and E2E CI, which needs pnpm to bypass its bundled gyp_main.py.
|
||||
# Historical refs can lack the shared action; retain their original install path.
|
||||
- name: Use external node-gyp to avoid pnpm's bundled copy
|
||||
if: steps.install-mode.outputs.shared != 'true'
|
||||
run: |
|
||||
npm install -g node-gyp@11.5.0
|
||||
echo "npm_config_node_gyp=$(npm root -g)/node-gyp/bin/node-gyp.js" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Install dependencies
|
||||
if: steps.install-mode.outputs.shared != 'true'
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Build Electron app for terminal perf
|
||||
|
||||
@@ -26,6 +26,7 @@ jobs:
|
||||
test:
|
||||
name: tests node ${{ matrix.node }} ${{ matrix.shard.index }}/${{ matrix.shard.count }}
|
||||
runs-on: ${{ inputs.runner }}
|
||||
timeout-minutes: 60
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
@@ -82,6 +83,7 @@ jobs:
|
||||
matrix:
|
||||
node: ${{ fromJSON(inputs.node_versions) }}
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 60
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
@@ -103,8 +105,8 @@ jobs:
|
||||
- name: Install relay integration dependencies
|
||||
working-directory: cloud
|
||||
run: |
|
||||
npx --yes pnpm@10.24.0 --filter '@orca-cloud/relay...' install --frozen-lockfile --ignore-scripts
|
||||
npx --yes pnpm@10.24.0 --filter '@orca-cloud/relay^...' build
|
||||
npx --yes pnpm@10.34.6 --filter '@orca-cloud/relay...' install --frozen-lockfile --ignore-scripts
|
||||
npx --yes pnpm@10.34.6 --filter '@orca-cloud/relay^...' build
|
||||
|
||||
- name: Test relay integration contracts
|
||||
env:
|
||||
|
||||
Reference in New Issue
Block a user