diff --git a/.github/workflows/android-compile.yml b/.github/workflows/android-compile.yml
index 7eff50674..e6989f0bf 100644
--- a/.github/workflows/android-compile.yml
+++ b/.github/workflows/android-compile.yml
@@ -90,7 +90,7 @@ jobs:
version_code: ${{ steps.version.outputs.version_code }}
steps:
- name: Checkout code
- uses: actions/checkout@v5
+ uses: actions/checkout@v7
with:
ref: ${{ inputs.build_ref || github.ref }}
fetch-depth: 1
@@ -118,7 +118,7 @@ jobs:
java-version: "17"
- name: Set up Android SDK
- uses: android-actions/setup-android@v3
+ uses: android-actions/setup-android@v4
- name: Install Android SDK packages
shell: bash
@@ -130,10 +130,12 @@ jobs:
"ndk;27.0.12077973"
- name: Set up pnpm
- uses: pnpm/action-setup@v5
+ uses: pnpm/action-setup@v6
+ with:
+ version: 10.10.0
- name: Set up Node
- uses: actions/setup-node@v5
+ uses: actions/setup-node@v6
with:
node-version: "24"
cache: "pnpm"
@@ -188,7 +190,7 @@ jobs:
echo "Android versionName=$version_name versionCode=$version_code"
- name: Upload unsigned AAB artifact
- uses: actions/upload-artifact@v4
+ uses: actions/upload-artifact@v7
with:
name: openhuman-android-aab-unsigned
path: ${{ steps.aab.outputs.path }}
@@ -204,7 +206,7 @@ jobs:
environment: Production
steps:
- name: Download unsigned AAB
- uses: actions/download-artifact@v4
+ uses: actions/download-artifact@v8
with:
name: openhuman-android-aab-unsigned
path: android-release
@@ -250,7 +252,7 @@ jobs:
echo "path=signed/openhuman-android-release.aab" >> "$GITHUB_OUTPUT"
- name: Upload signed AAB artifact
- uses: actions/upload-artifact@v4
+ uses: actions/upload-artifact@v7
with:
name: openhuman-android-aab-signed
path: ${{ steps.sign.outputs.path }}
@@ -258,7 +260,7 @@ jobs:
retention-days: 30
- name: Upload to Google Play
- uses: r0adkll/upload-google-play@v1.1.4
+ uses: r0adkll/upload-google-play@v1.1.5
with:
serviceAccountJsonPlainText: ${{ secrets.GOOGLE_PLAY_SERVICE_ACCOUNT_JSON }}
packageName: com.openhuman.app
diff --git a/.github/workflows/build-ci-image.yml b/.github/workflows/build-ci-image.yml
index 753fe6f04..4b2700733 100644
--- a/.github/workflows/build-ci-image.yml
+++ b/.github/workflows/build-ci-image.yml
@@ -13,18 +13,18 @@ jobs:
environment: Production
steps:
- name: Checkout code
- uses: actions/checkout@v5
+ uses: actions/checkout@v7
with:
# vendored tauri-cef fork is compiled into the image
submodules: recursive
- name: Log in to GHCR
- uses: docker/login-action@v3
+ uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
- uses: docker/build-push-action@v6
+ uses: docker/build-push-action@v7
with:
context: .
file: .github/Dockerfile
diff --git a/.github/workflows/build-desktop.yml b/.github/workflows/build-desktop.yml
index b9492b33c..3420b76c9 100644
--- a/.github/workflows/build-desktop.yml
+++ b/.github/workflows/build-desktop.yml
@@ -133,7 +133,7 @@ jobs:
VITE_TELEGRAM_BOT_USERNAME: ${{ inputs.telegram_bot_username }}
steps:
- name: Checkout build ref
- uses: actions/checkout@v5
+ uses: actions/checkout@v7
with:
ref: ${{ inputs.build_ref }}
fetch-depth: 1
@@ -144,15 +144,16 @@ jobs:
echo "[build-desktop] tag=${{ inputs.tag }} build_ref=${{ inputs.build_ref }}"
- name: Set Xcode version
if: matrix.settings.platform == 'macos-latest'
- uses: maxim-lobanov/setup-xcode@v1
+ uses: maxim-lobanov/setup-xcode@v1.7.0
with:
xcode-version: latest-stable
- name: Setup pnpm
- uses: pnpm/action-setup@v5
+ uses: pnpm/action-setup@v6
with:
+ version: 10.10.0
cache: true
- name: Setup Node.js 24.x
- uses: actions/setup-node@v5
+ uses: actions/setup-node@v6
with:
node-version: 24.x
- name: Install Rust (rust-toolchain.toml)
@@ -192,7 +193,7 @@ jobs:
run: |
echo "hash=$(tail -n +8 Cargo.lock | openssl dgst -sha256 | awk '{print $2}')" >> "$GITHUB_OUTPUT"
- name: Cache Cargo registry and git sources
- uses: actions/cache@v5
+ uses: actions/cache@v6
with:
path: |
~/.cargo/registry
@@ -206,7 +207,7 @@ jobs:
# runs. Default path is `dirs::cache_dir()/tauri-cef`.
- name: Cache CEF binary distribution (unix)
if: matrix.settings.platform != 'windows-latest'
- uses: actions/cache@v5
+ uses: actions/cache@v6
with:
path: |
~/Library/Caches/tauri-cef
@@ -216,7 +217,7 @@ jobs:
cef-${{ matrix.settings.target }}-
- name: Cache CEF binary distribution (windows)
if: matrix.settings.platform == 'windows-latest'
- uses: actions/cache@v5
+ uses: actions/cache@v6
with:
path: ~/AppData/Local/tauri-cef
key: cef-${{ matrix.settings.target }}-${{ hashFiles('app/src-tauri/Cargo.toml') }}
@@ -236,14 +237,14 @@ jobs:
- name: Cache vendored tauri-cli binary (unix)
if: matrix.settings.platform != 'windows-latest'
id: tauri-cli-cache-unix
- uses: actions/cache@v5
+ uses: actions/cache@v6
with:
path: ~/.cargo/bin/cargo-tauri
key: vendored-tauri-cli-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('app/src-tauri/vendor/tauri-cef/crates/tauri-cli/Cargo.toml') }}
- name: Cache vendored tauri-cli binary (windows)
if: matrix.settings.platform == 'windows-latest'
id: tauri-cli-cache-windows
- uses: actions/cache@v5
+ uses: actions/cache@v6
with:
path: ~/.cargo/bin/cargo-tauri.exe
key: vendored-tauri-cli-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('app/src-tauri/vendor/tauri-cef/crates/tauri-cli/Cargo.toml') }}
@@ -299,7 +300,7 @@ jobs:
# `KEYPAIR_ALIAS` (Windows DigiCert sign command). Pubkey + endpoint
# come from the static `app/src-tauri/tauri.conf.json`.
id: config-overrides
- uses: actions/github-script@v8
+ uses: actions/github-script@v9
env:
BASE_URL: ${{ inputs.base_url }}
WITH_UPDATER: ${{ inputs.with_updater && 'true' || 'false' }}
@@ -753,7 +754,7 @@ jobs:
# ---- Actions-artifact uploads (when not pushing to a GH Release) ------
- name: Upload desktop bundles as Actions artifact
if: "!inputs.with_release_upload"
- uses: actions/upload-artifact@v5
+ uses: actions/upload-artifact@v7
with:
name:
desktop-bundles-${{ matrix.settings.platform }}-${{ matrix.settings.artifact_suffix
@@ -763,7 +764,7 @@ jobs:
target/${{ matrix.settings.target }}/${{ inputs.build_profile }}/bundle/**
- name: Upload standalone CLI artifact
if: inputs.build_sidecar && !inputs.with_release_upload
- uses: actions/upload-artifact@v5
+ uses: actions/upload-artifact@v7
with:
name:
standalone-bins-${{ matrix.settings.platform }}-${{ matrix.settings.artifact_suffix
diff --git a/.github/workflows/ci-full.yml b/.github/workflows/ci-full.yml
index df7871573..a11644b21 100644
--- a/.github/workflows/ci-full.yml
+++ b/.github/workflows/ci-full.yml
@@ -82,7 +82,7 @@ jobs:
df -h /__w || true
- name: Checkout code
- uses: actions/checkout@v5
+ uses: actions/checkout@v7
with:
fetch-depth: 1
persist-credentials: false
@@ -90,7 +90,7 @@ jobs:
- name: Cache pnpm store
id: pnpm-cache
- uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
+ uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
with:
path: .pnpm-store
key: pnpm-store-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
@@ -111,7 +111,7 @@ jobs:
- name: Save pnpm store cache
if: always() && steps.pnpm-cache.outputs.cache-hit != 'true'
- uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
+ uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
with:
path: .pnpm-store
key: ${{ steps.pnpm-cache.outputs.cache-primary-key }}
@@ -139,7 +139,7 @@ jobs:
CARGO_INCREMENTAL: "0"
steps:
- name: Checkout code
- uses: actions/checkout@v5
+ uses: actions/checkout@v7
with:
fetch-depth: 1
persist-credentials: false
@@ -147,7 +147,7 @@ jobs:
- name: Cache pnpm store
id: pnpm-cache
- uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
+ uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
with:
path: .pnpm-store
key: pnpm-store-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
@@ -163,7 +163,7 @@ jobs:
- name: Restore cached Playwright E2E artifact
id: playwright-artifact-cache
- uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
+ uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
with:
path: .ci/artifacts/e2e-playwright-linux.tar.gz
key: e2e-playwright-linux-${{ hashFiles('src/**', 'Cargo.toml', 'Cargo.lock', 'rust-toolchain.toml', 'app/src/**', 'app/public/**', 'app/index.html', 'app/vite.config.*', 'app/tailwind.config.*', 'app/postcss.config.*', 'app/package.json', 'pnpm-lock.yaml', 'app/scripts/e2e-web-build.sh') }}
@@ -174,7 +174,7 @@ jobs:
- name: Save pnpm store cache
if: always() && steps.pnpm-cache.outputs.cache-hit != 'true'
- uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
+ uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
with:
path: .pnpm-store
key: ${{ steps.pnpm-cache.outputs.cache-primary-key }}
@@ -210,13 +210,13 @@ jobs:
- name: Save Playwright E2E artifact cache
if: always() && steps.playwright-artifact-cache.outputs.cache-hit != 'true' && hashFiles('.ci/artifacts/e2e-playwright-linux.tar.gz') != ''
- uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
+ uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
with:
path: .ci/artifacts/e2e-playwright-linux.tar.gz
key: ${{ steps.playwright-artifact-cache.outputs.cache-primary-key }}
- name: Upload Playwright E2E artifact
- uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: e2e-playwright-linux-${{ github.run_id }}
path: .ci/artifacts/e2e-playwright-linux.tar.gz
@@ -236,7 +236,7 @@ jobs:
continue-on-error: true
steps:
- name: Checkout code
- uses: actions/checkout@v5
+ uses: actions/checkout@v7
with:
fetch-depth: 1
persist-credentials: false
@@ -244,7 +244,7 @@ jobs:
- name: Cache pnpm store
id: pnpm-cache
- uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
+ uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
with:
path: .pnpm-store
key: pnpm-store-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
@@ -256,13 +256,13 @@ jobs:
- name: Save pnpm store cache
if: always() && steps.pnpm-cache.outputs.cache-hit != 'true'
- uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
+ uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
with:
path: .pnpm-store
key: ${{ steps.pnpm-cache.outputs.cache-primary-key }}
- name: Download Playwright E2E artifact
- uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
name: e2e-playwright-linux-${{ github.run_id }}
path: .
@@ -289,7 +289,7 @@ jobs:
- name: Upload Playwright E2E failure artifacts
if: failure()
- uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: e2e-playwright-failure-logs-${{ github.run_id }}
path: |
diff --git a/.github/workflows/ci-lite.yml b/.github/workflows/ci-lite.yml
index d188b3a77..2686f8cf6 100644
--- a/.github/workflows/ci-lite.yml
+++ b/.github/workflows/ci-lite.yml
@@ -75,7 +75,7 @@ jobs:
coverage: ${{ steps.filter.outputs.frontend == 'true' || steps.filter.outputs['rust-core'] == 'true' || steps.filter.outputs['rust-tauri'] == 'true' }}
steps:
- name: Checkout code
- uses: actions/checkout@v5
+ uses: actions/checkout@v7
- name: Detect changed paths
id: filter
@@ -193,10 +193,10 @@ jobs:
image: ghcr.io/tinyhumansai/openhuman_ci:rust-1.93.0
steps:
- name: Checkout code
- # Pinned to the v5 commit SHA for supply-chain hardening (CodeRabbit
+ # Pinned to the v7 commit SHA for supply-chain hardening (CodeRabbit
# review on #3892). The combined frontend lane keeps that hardening
# from the former docs-drift job.
- uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
+ uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
with:
fetch-depth: 1
persist-credentials: false
@@ -222,7 +222,7 @@ jobs:
- name: Cache pnpm store
id: pnpm-cache
if: needs.changes.outputs.frontend == 'true' || needs.changes.outputs.i18n == 'true'
- uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
+ uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
with:
path: .pnpm-store
key: pnpm-store-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
@@ -235,7 +235,7 @@ jobs:
- name: Save pnpm store cache
if: always() && (needs.changes.outputs.frontend == 'true' || needs.changes.outputs.i18n == 'true') && steps.pnpm-cache.outputs.cache-hit != 'true'
- uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
+ uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
with:
path: .pnpm-store
key: ${{ steps.pnpm-cache.outputs.cache-primary-key }}
@@ -290,7 +290,7 @@ jobs:
- name: Upload frontend lcov
if: needs.changes.outputs.frontend == 'true'
- uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: lcov-frontend
path: app/coverage/lcov.info
@@ -309,7 +309,7 @@ jobs:
CARGO_INCREMENTAL: "0"
steps:
- name: Checkout code
- uses: actions/checkout@v5
+ uses: actions/checkout@v7
with:
fetch-depth: 1
persist-credentials: false
@@ -376,7 +376,7 @@ jobs:
df -h /__w || true
- name: Checkout code
- uses: actions/checkout@v5
+ uses: actions/checkout@v7
with:
fetch-depth: 1
persist-credentials: false
@@ -420,7 +420,7 @@ jobs:
df -h /__w || true
- name: Upload core lcov
- uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: lcov-rust-core
path: lcov-core.info
@@ -462,7 +462,7 @@ jobs:
df -h /__w || true
- name: Checkout code
- uses: actions/checkout@v5
+ uses: actions/checkout@v7
with:
fetch-depth: 1
persist-credentials: false
@@ -481,7 +481,7 @@ jobs:
- name: Cache CEF binary distribution
id: cef-cache
- uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
+ uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
with:
path: |
~/Library/Caches/tauri-cef
@@ -503,7 +503,7 @@ jobs:
- name: Save CEF binary distribution cache
if: always() && steps.cef-cache.outputs.cache-hit != 'true'
- uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
+ uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
with:
path: |
~/Library/Caches/tauri-cef
@@ -511,7 +511,7 @@ jobs:
key: ${{ steps.cef-cache.outputs.cache-primary-key }}
- name: Upload tauri lcov
- uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: lcov-rust-tauri
path: lcov-tauri.info
@@ -528,14 +528,14 @@ jobs:
image: ghcr.io/tinyhumansai/openhuman_ci:rust-1.93.0
steps:
- name: Checkout code
- uses: actions/checkout@v5
+ uses: actions/checkout@v7
with:
fetch-depth: 1
persist-credentials: false
- name: Cache pnpm store
id: pnpm-cache
- uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
+ uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
with:
path: .pnpm-store
key: pnpm-store-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
@@ -549,7 +549,7 @@ jobs:
- name: Save pnpm store cache
if: always() && steps.pnpm-cache.outputs.cache-hit != 'true'
- uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
+ uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
with:
path: .pnpm-store
key: ${{ steps.pnpm-cache.outputs.cache-primary-key }}
@@ -567,7 +567,7 @@ jobs:
image: ghcr.io/tinyhumansai/openhuman_ci:rust-1.93.0
steps:
- name: Checkout code
- uses: actions/checkout@v5
+ uses: actions/checkout@v7
with:
fetch-depth: 1
persist-credentials: false
@@ -588,7 +588,7 @@ jobs:
timeout-minutes: 10
steps:
- name: Checkout code
- uses: actions/checkout@v5
+ uses: actions/checkout@v7
with:
fetch-depth: 1
persist-credentials: false
@@ -678,7 +678,7 @@ jobs:
- name: Checkout code
if: needs.changes.outputs.coverage == 'true'
- uses: actions/checkout@v5
+ uses: actions/checkout@v7
with:
fetch-depth: 0
@@ -708,7 +708,7 @@ jobs:
- name: Download all lcov artifacts
if: needs.changes.outputs.coverage == 'true'
- uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
path: lcov-artifacts
pattern: lcov-*
@@ -737,7 +737,7 @@ jobs:
- name: Upload diff-cover report
if: always() && needs.changes.outputs.coverage == 'true'
- uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: diff-coverage-report
path: |
diff --git a/.github/workflows/e2e-agent-review.yml b/.github/workflows/e2e-agent-review.yml
index d49e74a65..9df17282f 100644
--- a/.github/workflows/e2e-agent-review.yml
+++ b/.github/workflows/e2e-agent-review.yml
@@ -30,7 +30,7 @@ jobs:
timeout-minutes: 30
steps:
- name: Checkout code
- uses: actions/checkout@v5
+ uses: actions/checkout@v7
with:
fetch-depth: 1
submodules: recursive
@@ -45,12 +45,13 @@ jobs:
fi
- name: Setup pnpm
if: steps.gate.outputs.present == 'true'
- uses: pnpm/action-setup@v5
+ uses: pnpm/action-setup@v6
with:
+ version: 10.10.0
cache: true
- name: Setup Node.js 24.x
if: steps.gate.outputs.present == 'true'
- uses: actions/setup-node@v5
+ uses: actions/setup-node@v6
with:
node-version: 24.x
- name: Install Rust (rust-toolchain.toml)
@@ -74,13 +75,14 @@ jobs:
echo "hash=$(tail -n +8 Cargo.lock | openssl dgst -sha256 | awk '{print $2}')" >> "$GITHUB_OUTPUT"
- name: Cache Cargo registry and build
if: steps.gate.outputs.present == 'true'
- uses: actions/cache@v5
+ uses: actions/cache@v6
with:
path: |
~/.cargo/registry
~/.cargo/git
target
- key: ${{ runner.os }}-e2e-agentreview-cargo-${{ steps.cargo-lock-fingerprint.outputs.hash
+ key:
+ ${{ runner.os }}-e2e-agentreview-cargo-${{ steps.cargo-lock-fingerprint.outputs.hash
}}
restore-keys: |
${{ runner.os }}-e2e-agentreview-cargo-
@@ -128,7 +130,7 @@ jobs:
fi
- name: Upload E2E artifacts
if: always() && steps.gate.outputs.present == 'true'
- uses: actions/upload-artifact@v5
+ uses: actions/upload-artifact@v7
with:
name: e2e-agent-review-artifacts
path: |
diff --git a/.github/workflows/e2e-playwright.yml b/.github/workflows/e2e-playwright.yml
index 6c80b6fdf..b99adf648 100644
--- a/.github/workflows/e2e-playwright.yml
+++ b/.github/workflows/e2e-playwright.yml
@@ -29,14 +29,14 @@ jobs:
timeout-minutes: 30
steps:
- name: Checkout code
- uses: actions/checkout@v5
+ uses: actions/checkout@v7
with:
fetch-depth: 1
persist-credentials: false
submodules: recursive
- name: Cache pnpm store
- uses: actions/cache@v5
+ uses: actions/cache@v6
with:
path: ~/.local/share/pnpm/store
key: pnpm-store-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
@@ -75,7 +75,7 @@ jobs:
- name: Upload Playwright E2E failure artifacts
if: failure()
- uses: actions/upload-artifact@v5
+ uses: actions/upload-artifact@v7
with:
name: e2e-playwright-failure-logs-${{ github.run_id }}
path: |
diff --git a/.github/workflows/e2e-reusable.yml b/.github/workflows/e2e-reusable.yml
index 8125bf6ec..e22ea485e 100644
--- a/.github/workflows/e2e-reusable.yml
+++ b/.github/workflows/e2e-reusable.yml
@@ -89,7 +89,7 @@ jobs:
timeout-minutes: 30
steps:
- name: Checkout code
- uses: actions/checkout@v5
+ uses: actions/checkout@v7
with:
ref: ${{ inputs.ref }}
fetch-depth: 1
@@ -97,7 +97,7 @@ jobs:
submodules: recursive
- name: Cache pnpm store
- uses: actions/cache@v5
+ uses: actions/cache@v6
with:
path: ~/.local/share/pnpm/store
key: pnpm-store-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
@@ -117,7 +117,7 @@ jobs:
# build-desktop.yml so a release build and an E2E run on the same
# commit can share a single download.
- name: Cache CEF binary distribution
- uses: actions/cache@v5
+ uses: actions/cache@v6
with:
path: |
~/.cache/tauri-cef
@@ -126,7 +126,7 @@ jobs:
cef-x86_64-unknown-linux-gnu-
- name: Cache Appium global install
- uses: actions/cache@v5
+ uses: actions/cache@v6
with:
path: |
~/.appium
@@ -165,7 +165,7 @@ jobs:
- name: Upload E2E failure artifacts
if: failure()
- uses: actions/upload-artifact@v5
+ uses: actions/upload-artifact@v7
with:
name: e2e-failure-logs-${{ runner.os }}-${{ github.run_id }}
path: |
@@ -202,14 +202,14 @@ jobs:
timeout-minutes: 30
steps:
- name: Checkout code
- uses: actions/checkout@v5
+ uses: actions/checkout@v7
with:
ref: ${{ inputs.ref }}
fetch-depth: 1
submodules: recursive
- name: Cache pnpm store
- uses: actions/cache@v5
+ uses: actions/cache@v6
with:
path: ~/.local/share/pnpm/store
key: pnpm-store-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
@@ -226,7 +226,7 @@ jobs:
key: e2e-linux-unified
- name: Cache CEF binary distribution
- uses: actions/cache@v5
+ uses: actions/cache@v6
with:
# cef-dll-sys downloads into $CEF_PATH; ensure-tauri-cli.sh +
# e2e-build.sh pin that to $HOME/Library/Caches/tauri-cef on
@@ -264,7 +264,7 @@ jobs:
ls -lh e2e-build-linux.tar.gz
- name: Upload build artifact
- uses: actions/upload-artifact@v5
+ uses: actions/upload-artifact@v7
with:
name: e2e-build-linux-${{ github.run_id }}
path: e2e-build-linux.tar.gz
@@ -286,19 +286,20 @@ jobs:
- { name: foundation, suites: "auth,navigation,system" }
- { name: chat, suites: "chat,skills,journeys" }
- { name: providers, suites: "providers,notifications" }
+ - { name: provider-web, suites: "provider-web" }
- { name: webhooks, suites: "webhooks" }
- { name: connectors, suites: "connectors" }
- { name: commerce, suites: "payments,settings" }
steps:
- name: Checkout code
- uses: actions/checkout@v5
+ uses: actions/checkout@v7
with:
ref: ${{ inputs.ref }}
fetch-depth: 1
submodules: recursive
- name: Cache pnpm store
- uses: actions/cache@v5
+ uses: actions/cache@v6
with:
path: ~/.local/share/pnpm/store
key: pnpm-store-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
@@ -306,7 +307,7 @@ jobs:
pnpm-store-${{ runner.os }}-
- name: Cache Appium global install
- uses: actions/cache@v5
+ uses: actions/cache@v6
with:
path: |
~/.appium
@@ -325,7 +326,7 @@ jobs:
bash scripts/ci-cancel-aware.sh appium driver install --source=npm appium-chromium-driver >/dev/null 2>&1 || true
- name: Download build artifact
- uses: actions/download-artifact@v5
+ uses: actions/download-artifact@v8
with:
name: e2e-build-linux-${{ github.run_id }}
path: .
@@ -360,7 +361,7 @@ jobs:
- name: Upload E2E failure artifacts
if: failure()
- uses: actions/upload-artifact@v5
+ uses: actions/upload-artifact@v7
with:
name: e2e-failure-logs-${{ runner.os }}-${{ matrix.shard.name }}-${{ github.run_id }}
path: |
@@ -398,7 +399,7 @@ jobs:
RUST_BACKTRACE: "1"
steps:
- name: Checkout code
- uses: actions/checkout@v5
+ uses: actions/checkout@v7
with:
ref: ${{ inputs.ref }}
fetch-depth: 1
@@ -406,7 +407,7 @@ jobs:
submodules: recursive
- name: Cache pnpm store
- uses: actions/cache@v5
+ uses: actions/cache@v6
with:
path: ~/.local/share/pnpm/store
key: pnpm-store-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
@@ -442,7 +443,7 @@ jobs:
timeout-minutes: 30
steps:
- name: Checkout code
- uses: actions/checkout@v5
+ uses: actions/checkout@v7
with:
ref: ${{ inputs.ref }}
fetch-depth: 1
@@ -450,10 +451,12 @@ jobs:
submodules: recursive
- name: Install pnpm
- uses: pnpm/action-setup@v4
+ uses: pnpm/action-setup@v6
+ with:
+ version: 10.10.0
- name: Setup Node.js 24.x
- uses: actions/setup-node@v5
+ uses: actions/setup-node@v6
with:
node-version: 24.x
cache: pnpm
@@ -490,7 +493,7 @@ jobs:
key: e2e-macos-unified-v2
- name: Cache CEF binary distribution
- uses: actions/cache@v5
+ uses: actions/cache@v6
with:
path: |
~/Library/Caches/tauri-cef
@@ -499,7 +502,7 @@ jobs:
cef-aarch64-apple-darwin-
- name: Cache Appium global install
- uses: actions/cache@v5
+ uses: actions/cache@v6
with:
path: |
~/.appium
@@ -555,7 +558,7 @@ jobs:
timeout-minutes: 30
steps:
- name: Checkout code
- uses: actions/checkout@v5
+ uses: actions/checkout@v7
with:
ref: ${{ inputs.ref }}
fetch-depth: 1
@@ -563,10 +566,12 @@ jobs:
submodules: recursive
- name: Install pnpm
- uses: pnpm/action-setup@v4
+ uses: pnpm/action-setup@v6
+ with:
+ version: 10.10.0
- name: Setup Node.js 24.x
- uses: actions/setup-node@v5
+ uses: actions/setup-node@v6
with:
node-version: 24.x
cache: pnpm
@@ -584,7 +589,7 @@ jobs:
key: e2e-windows-unified
- name: Cache CEF binary distribution
- uses: actions/cache@v5
+ uses: actions/cache@v6
with:
path: |
~/AppData/Local/tauri-cef
@@ -593,7 +598,7 @@ jobs:
cef-x86_64-pc-windows-msvc-
- name: Cache Appium global install
- uses: actions/cache@v5
+ uses: actions/cache@v6
with:
path: |
~/.appium
@@ -649,17 +654,19 @@ jobs:
timeout-minutes: 30
steps:
- name: Checkout code
- uses: actions/checkout@v5
+ uses: actions/checkout@v7
with:
ref: ${{ inputs.ref }}
fetch-depth: 1
submodules: recursive
- name: Install pnpm
- uses: pnpm/action-setup@v4
+ uses: pnpm/action-setup@v6
+ with:
+ version: 10.10.0
- name: Setup Node.js 24.x
- uses: actions/setup-node@v5
+ uses: actions/setup-node@v6
with:
node-version: 24.x
cache: pnpm
@@ -697,7 +704,7 @@ jobs:
key: e2e-macos-unified-v2
- name: Cache CEF binary distribution
- uses: actions/cache@v5
+ uses: actions/cache@v6
with:
path: |
~/Library/Caches/tauri-cef
@@ -731,7 +738,7 @@ jobs:
ls -lh e2e-build-macos.tar.gz
- name: Upload build artifact
- uses: actions/upload-artifact@v5
+ uses: actions/upload-artifact@v7
with:
name: e2e-build-macos-${{ github.run_id }}
path: e2e-build-macos.tar.gz
@@ -751,28 +758,31 @@ jobs:
- { name: foundation, suites: "auth,navigation,system" }
- { name: chat, suites: "chat,skills,journeys" }
- { name: providers, suites: "providers,notifications" }
+ - { name: provider-web, suites: "provider-web" }
- { name: webhooks, suites: "webhooks" }
- { name: connectors, suites: "connectors" }
- { name: commerce, suites: "payments,settings" }
steps:
- name: Checkout code
- uses: actions/checkout@v5
+ uses: actions/checkout@v7
with:
ref: ${{ inputs.ref }}
fetch-depth: 1
submodules: recursive
- name: Install pnpm
- uses: pnpm/action-setup@v4
+ uses: pnpm/action-setup@v6
+ with:
+ version: 10.10.0
- name: Setup Node.js 24.x
- uses: actions/setup-node@v5
+ uses: actions/setup-node@v6
with:
node-version: 24.x
cache: pnpm
- name: Cache Appium global install
- uses: actions/cache@v5
+ uses: actions/cache@v6
with:
path: |
~/.appium
@@ -790,7 +800,7 @@ jobs:
bash scripts/ci-cancel-aware.sh appium driver install --source=npm appium-chromium-driver >/dev/null 2>&1 || true
- name: Download build artifact
- uses: actions/download-artifact@v5
+ uses: actions/download-artifact@v8
with:
name: e2e-build-macos-${{ github.run_id }}
path: .
@@ -831,7 +841,7 @@ jobs:
- name: Upload E2E failure artifacts
if: failure()
- uses: actions/upload-artifact@v5
+ uses: actions/upload-artifact@v7
with:
name: e2e-failure-logs-${{ runner.os }}-${{ matrix.shard.name }}-${{ github.run_id }}
path: |
@@ -866,17 +876,19 @@ jobs:
timeout-minutes: 30
steps:
- name: Checkout code
- uses: actions/checkout@v5
+ uses: actions/checkout@v7
with:
ref: ${{ inputs.ref }}
fetch-depth: 1
submodules: recursive
- name: Install pnpm
- uses: pnpm/action-setup@v4
+ uses: pnpm/action-setup@v6
+ with:
+ version: 10.10.0
- name: Setup Node.js 24.x
- uses: actions/setup-node@v5
+ uses: actions/setup-node@v6
with:
node-version: 24.x
cache: pnpm
@@ -894,7 +906,7 @@ jobs:
key: e2e-windows-unified
- name: Cache CEF binary distribution
- uses: actions/cache@v5
+ uses: actions/cache@v6
with:
# ensure-tauri-cli.sh + e2e-build.sh export
# CEF_PATH=$HOME/Library/Caches/tauri-cef regardless of OS; under Git
@@ -934,7 +946,7 @@ jobs:
ls -lh e2e-build-windows.tar.gz
- name: Upload build artifact
- uses: actions/upload-artifact@v5
+ uses: actions/upload-artifact@v7
with:
name: e2e-build-windows-${{ github.run_id }}
path: e2e-build-windows.tar.gz
@@ -955,28 +967,31 @@ jobs:
- { name: foundation, suites: "auth,navigation,system" }
- { name: chat, suites: "chat,skills,journeys" }
- { name: providers, suites: "providers,notifications" }
+ - { name: provider-web, suites: "provider-web" }
- { name: webhooks, suites: "webhooks" }
- { name: connectors, suites: "connectors" }
- { name: commerce, suites: "payments,settings" }
steps:
- name: Checkout code
- uses: actions/checkout@v5
+ uses: actions/checkout@v7
with:
ref: ${{ inputs.ref }}
fetch-depth: 1
submodules: recursive
- name: Install pnpm
- uses: pnpm/action-setup@v4
+ uses: pnpm/action-setup@v6
+ with:
+ version: 10.10.0
- name: Setup Node.js 24.x
- uses: actions/setup-node@v5
+ uses: actions/setup-node@v6
with:
node-version: 24.x
cache: pnpm
- name: Cache Appium global install
- uses: actions/cache@v5
+ uses: actions/cache@v6
with:
path: |
~/.appium
@@ -995,7 +1010,7 @@ jobs:
bash scripts/ci-cancel-aware.sh appium driver install --source=npm appium-chromium-driver >/dev/null 2>&1 || true
- name: Download build artifact
- uses: actions/download-artifact@v5
+ uses: actions/download-artifact@v8
with:
name: e2e-build-windows-${{ github.run_id }}
path: .
@@ -1028,7 +1043,7 @@ jobs:
- name: Upload E2E failure artifacts
if: failure()
- uses: actions/upload-artifact@v5
+ uses: actions/upload-artifact@v7
with:
name: e2e-failure-logs-${{ runner.os }}-${{ matrix.shard.name }}-${{ github.run_id }}
# e2e-run-session.sh writes its app log to `${RUNNER_TEMP:-${TMPDIR:-/tmp}}`.
diff --git a/.github/workflows/ios-appstore.yml b/.github/workflows/ios-appstore.yml
index 41ebaef8c..c088104c9 100644
--- a/.github/workflows/ios-appstore.yml
+++ b/.github/workflows/ios-appstore.yml
@@ -49,7 +49,7 @@ jobs:
APPLE_DEVELOPMENT_TEAM: ${{ secrets.APPLE_TEAM_ID }}
steps:
- name: Checkout
- uses: actions/checkout@v4
+ uses: actions/checkout@v7
with:
ref: ${{ inputs.ref || github.ref }}
fetch-depth: 1
@@ -71,10 +71,12 @@ jobs:
cache-on-failure: true
- name: Set up pnpm
- uses: pnpm/action-setup@v4
+ uses: pnpm/action-setup@v6
+ with:
+ version: 10.10.0
- name: Set up Node
- uses: actions/setup-node@v4
+ uses: actions/setup-node@v6
with:
node-version: "24"
cache: "pnpm"
@@ -294,7 +296,7 @@ jobs:
- name: Upload IPA artifact
if: always() && steps.export.outputs.ipa_path != ''
- uses: actions/upload-artifact@v4
+ uses: actions/upload-artifact@v7
with:
name: openhuman-ios-ipa
path: ${{ steps.export.outputs.ipa_path }}
@@ -302,7 +304,7 @@ jobs:
- name: Upload archive dSYMs
if: always()
- uses: actions/upload-artifact@v4
+ uses: actions/upload-artifact@v7
with:
name: openhuman-ios-dsyms
path: app/src-tauri-mobile/gen/apple/build/openhuman-mobile_iOS.xcarchive/dSYMs
diff --git a/.github/workflows/ios-compile.yml b/.github/workflows/ios-compile.yml
index f0b4bd356..8e28b1039 100644
--- a/.github/workflows/ios-compile.yml
+++ b/.github/workflows/ios-compile.yml
@@ -32,7 +32,7 @@ jobs:
IPHONEOS_DEPLOYMENT_TARGET: "16.0"
steps:
- name: Checkout code
- uses: actions/checkout@v4
+ uses: actions/checkout@v7
with:
fetch-depth: 1
# The mobile crate uses stock Tauri (no CEF), so we don't need
@@ -57,10 +57,12 @@ jobs:
cache-on-failure: true
- name: Set up pnpm
- uses: pnpm/action-setup@v4
+ uses: pnpm/action-setup@v6
+ with:
+ version: 10.10.0
- name: Set up Node
- uses: actions/setup-node@v4
+ uses: actions/setup-node@v6
with:
node-version: "24"
cache: "pnpm"
diff --git a/.github/workflows/pr-quality.yml b/.github/workflows/pr-quality.yml
index 35b24d1dd..157c15e7b 100644
--- a/.github/workflows/pr-quality.yml
+++ b/.github/workflows/pr-quality.yml
@@ -25,7 +25,7 @@ jobs:
if: ${{ !contains(github.event.pull_request.labels.*.name, 'docs') && !contains(github.event.pull_request.labels.*.name, 'chore') }}
steps:
- name: Checkout code
- uses: actions/checkout@v5
+ uses: actions/checkout@v7
with:
fetch-depth: 1
- name: Verify Submission Checklist
@@ -42,7 +42,7 @@ jobs:
if: ${{ !contains(github.event.pull_request.labels.*.name, 'docs') && !contains(github.event.pull_request.labels.*.name, 'chore') }}
steps:
- name: Checkout code
- uses: actions/checkout@v5
+ uses: actions/checkout@v7
with:
fetch-depth: 1
- name: Verify Coverage Matrix
@@ -55,7 +55,7 @@ jobs:
if: ${{ !contains(github.event.pull_request.labels.*.name, 'docs') && !contains(github.event.pull_request.labels.*.name, 'chore') }}
steps:
- name: Checkout code
- uses: actions/checkout@v5
+ uses: actions/checkout@v7
with:
fetch-depth: 1
- name: Lychee link check
@@ -84,7 +84,7 @@ jobs:
if: ${{ !contains(github.event.pull_request.labels.*.name, 'docs') && !contains(github.event.pull_request.labels.*.name, 'chore') }}
steps:
- name: Checkout code
- uses: actions/checkout@v5
+ uses: actions/checkout@v7
with:
fetch-depth: 1
- name: Install patchelf
diff --git a/.github/workflows/promote-main-to-release.yml b/.github/workflows/promote-main-to-release.yml
index 7ca0603e6..983fa9b7e 100644
--- a/.github/workflows/promote-main-to-release.yml
+++ b/.github/workflows/promote-main-to-release.yml
@@ -52,7 +52,7 @@ jobs:
permission-contents: write
- name: Checkout main
- uses: actions/checkout@v5
+ uses: actions/checkout@v7
with:
ref: main
fetch-depth: 0
diff --git a/.github/workflows/release-notes-preview.yml b/.github/workflows/release-notes-preview.yml
index 8bfbf3fbb..681e613c5 100644
--- a/.github/workflows/release-notes-preview.yml
+++ b/.github/workflows/release-notes-preview.yml
@@ -45,14 +45,14 @@ jobs:
environment: Production
steps:
- name: Checkout
- uses: actions/checkout@v4
+ uses: actions/checkout@v7
with:
fetch-depth: 0
persist-credentials: false
- name: Setup Node
- uses: actions/setup-node@v4
+ uses: actions/setup-node@v6
with:
- node-version: 22
+ node-version: 24
- name: Generate notes
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -79,7 +79,7 @@ jobs:
node scripts/release/generate-release-notes.mjs "${ARGS[@]}"
- name: Upload as artifact
- uses: actions/upload-artifact@v4
+ uses: actions/upload-artifact@v7
with:
name: release-notes-preview
path: release-notes-preview.md
diff --git a/.github/workflows/release-packages.yml b/.github/workflows/release-packages.yml
index 52942f5b2..9b1c1bb22 100644
--- a/.github/workflows/release-packages.yml
+++ b/.github/workflows/release-packages.yml
@@ -25,7 +25,6 @@ concurrency:
group: release-packages-${{ github.event.release.tag_name }}
cancel-in-progress: false
jobs:
-
# ────────────────────────────────────────────────────────────────────────────
# 1. Build Linux arm64 CLI tarball (native runner)
# Requires: ubuntu-24.04-arm GitHub-hosted runner (free for public repos).
@@ -42,7 +41,7 @@ jobs:
GH_TOKEN: ${{ github.token }}
steps:
- name: Checkout tag
- uses: actions/checkout@v5
+ uses: actions/checkout@v7
with:
ref: ${{ github.event.release.tag_name }}
fetch-depth: 1
@@ -103,12 +102,12 @@ jobs:
needs: [build-cli-linux-arm64]
steps:
- name: Checkout main repo (for formula template)
- uses: actions/checkout@v5
+ uses: actions/checkout@v7
with:
ref: ${{ github.event.release.tag_name }}
path: src
- name: Checkout Homebrew tap
- uses: actions/checkout@v5
+ uses: actions/checkout@v7
with:
repository: tinyhumansai/homebrew-openhuman
token: ${{ secrets.HOMEBREW_TAP_TOKEN }}
@@ -135,7 +134,7 @@ jobs:
needs: [build-cli-linux-arm64]
steps:
- name: Checkout tag
- uses: actions/checkout@v5
+ uses: actions/checkout@v7
with:
ref: ${{ github.event.release.tag_name }}
fetch-depth: 1
@@ -151,7 +150,7 @@ jobs:
echo "$APT_SIGNING_KEY" | gpg --batch --import
gpg --list-secret-keys
- name: Checkout gh-pages branch
- uses: actions/checkout@v5
+ uses: actions/checkout@v7
with:
ref: gh-pages
path: gh-pages
@@ -175,14 +174,16 @@ jobs:
timeout-minutes: 10
steps:
- name: Checkout tag
- uses: actions/checkout@v5
+ uses: actions/checkout@v7
with:
ref: ${{ github.event.release.tag_name }}
fetch-depth: 1
- name: Setup pnpm
- uses: pnpm/action-setup@v5
+ uses: pnpm/action-setup@v6
+ with:
+ version: 10.10.0
- name: Setup Node.js
- uses: actions/setup-node@v5
+ uses: actions/setup-node@v6
with:
node-version: 24.x
registry-url: https://registry.npmjs.org
@@ -257,7 +258,7 @@ jobs:
os: [ubuntu-latest, macos-latest]
steps:
- name: Setup Node.js
- uses: actions/setup-node@v5
+ uses: actions/setup-node@v6
with:
node-version: 24.x
- name: Wait for npm propagation, then install
@@ -280,7 +281,7 @@ jobs:
timeout-minutes: 5
steps:
- name: Create issue if it doesn't exist
- uses: actions/github-script@v8
+ uses: actions/github-script@v9
with:
script: |-
const { owner, repo } = context.repo;
diff --git a/.github/workflows/release-production.yml b/.github/workflows/release-production.yml
index 836b49c6d..c15c7a901 100644
--- a/.github/workflows/release-production.yml
+++ b/.github/workflows/release-production.yml
@@ -139,16 +139,18 @@ jobs:
# identity in the ruleset bypass list, not from token scopes.
permission-contents: write
- name: Checkout release
- uses: actions/checkout@v5
+ uses: actions/checkout@v7
with:
ref: release
fetch-depth: 0
token: ${{ steps.app-token.outputs.token }}
submodules: recursive
- name: Setup pnpm
- uses: pnpm/action-setup@v5
+ uses: pnpm/action-setup@v6
+ with:
+ version: 10.10.0
- name: Setup Node.js
- uses: actions/setup-node@v5
+ uses: actions/setup-node@v6
with:
node-version: 24.x
package-manager-cache: false
@@ -281,7 +283,7 @@ jobs:
echo "upload_url=" >> "$GITHUB_OUTPUT"
- name: Checkout release ref
if: ${{ inputs.create_release }}
- uses: actions/checkout@v5
+ uses: actions/checkout@v7
with:
ref: ${{ needs.prepare-build.outputs.build_ref }}
fetch-depth: 0
@@ -323,7 +325,7 @@ jobs:
- name: Create draft release with generated notes
if: ${{ inputs.create_release }}
id: create
- uses: actions/github-script@v8
+ uses: actions/github-script@v9
with:
script: |
const fs = require('fs');
@@ -414,7 +416,7 @@ jobs:
IMAGE_NAME: tinyhumansai/openhuman-core
steps:
- name: Checkout build ref
- uses: actions/checkout@v5
+ uses: actions/checkout@v7
with:
ref: ${{ needs.prepare-build.outputs.build_ref }}
fetch-depth: 1
@@ -424,9 +426,9 @@ jobs:
- name: Init vendored Rust submodules
run: git submodule update --init vendor/tinyagents vendor/tinyflows vendor/tinycortex vendor/tinyjuice vendor/tinychannels vendor/tinyplace
- name: Set up Docker Buildx
- uses: docker/setup-buildx-action@v3
+ uses: docker/setup-buildx-action@v4
- name: Log in to GHCR
- uses: docker/login-action@v3
+ uses: docker/login-action@v4
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
@@ -448,7 +450,7 @@ jobs:
echo "EOF"
} >> "$GITHUB_OUTPUT"
- name: Build and push image
- uses: docker/build-push-action@v6
+ uses: docker/build-push-action@v7
with:
context: .
file: Dockerfile
@@ -499,7 +501,7 @@ jobs:
GH_TOKEN: ${{ github.token }}
steps:
- name: Checkout build ref
- uses: actions/checkout@v5
+ uses: actions/checkout@v7
with:
ref: ${{ needs.prepare-build.outputs.build_ref }}
fetch-depth: 1
@@ -561,7 +563,7 @@ jobs:
environment: Production
steps:
- name: Checkout build ref
- uses: actions/checkout@v5
+ uses: actions/checkout@v7
with:
ref: ${{ needs.prepare-build.outputs.build_ref }}
fetch-depth: 1
@@ -599,7 +601,7 @@ jobs:
&& needs.publish-updater-manifest.result == 'success'
steps:
- name: Checkout validation scripts
- uses: actions/checkout@v5
+ uses: actions/checkout@v7
with:
ref: ${{ needs.prepare-build.outputs.build_ref }}
fetch-depth: 1
@@ -625,7 +627,7 @@ jobs:
scripts/validate-release-assets.sh /tmp/openhuman-release.json /tmp/latest.json
- name: Validate required installer assets exist
- uses: actions/github-script@v8
+ uses: actions/github-script@v9
with:
script: |
const releaseId = Number('${{ needs.create-release.outputs.release_id }}');
@@ -670,7 +672,7 @@ jobs:
core.info('All required installer assets are present.');
- name: Publish release
- uses: actions/github-script@v8
+ uses: actions/github-script@v9
with:
script: |
const releaseId = Number('${{ needs.create-release.outputs.release_id }}');
@@ -706,9 +708,9 @@ jobs:
IMAGE_NAME: tinyhumansai/openhuman-core
steps:
- name: Set up Docker Buildx
- uses: docker/setup-buildx-action@v3
+ uses: docker/setup-buildx-action@v4
- name: Log in to GHCR
- uses: docker/login-action@v3
+ uses: docker/login-action@v4
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
@@ -794,7 +796,7 @@ jobs:
steps:
- name: Delete GitHub release
if: ${{ inputs.create_release && needs.create-release.result == 'success' }}
- uses: actions/github-script@v8
+ uses: actions/github-script@v9
with:
script: |
const owner = context.repo.owner;
@@ -811,7 +813,7 @@ jobs:
core.warning(`deleteRelease failed: ${e.message}`);
}
- name: Delete remote tag
- uses: actions/github-script@v8
+ uses: actions/github-script@v9
with:
script: |
const owner = context.repo.owner;
diff --git a/.github/workflows/release-staging.yml b/.github/workflows/release-staging.yml
index 79a796ff6..053c97b5b 100644
--- a/.github/workflows/release-staging.yml
+++ b/.github/workflows/release-staging.yml
@@ -114,16 +114,18 @@ jobs:
# identity in the ruleset bypass list, not from token scopes.
permission-contents: write
- name: Checkout release
- uses: actions/checkout@v5
+ uses: actions/checkout@v7
with:
ref: release
fetch-depth: 0
token: ${{ steps.app-token.outputs.token }}
submodules: recursive
- name: Setup pnpm
- uses: pnpm/action-setup@v5
+ uses: pnpm/action-setup@v6
+ with:
+ version: 10.10.0
- name: Setup Node.js
- uses: actions/setup-node@v5
+ uses: actions/setup-node@v6
with:
node-version: 24.x
package-manager-cache: false
@@ -309,7 +311,7 @@ jobs:
environment: Production
steps:
- name: Checkout build ref
- uses: actions/checkout@v5
+ uses: actions/checkout@v7
with:
ref: ${{ needs.prepare-build.outputs.build_ref }}
fetch-depth: 1
@@ -319,9 +321,9 @@ jobs:
- name: Init vendored Rust submodules
run: git submodule update --init vendor/tinyagents vendor/tinyflows vendor/tinycortex vendor/tinyjuice vendor/tinychannels vendor/tinyplace
- name: Set up Docker Buildx
- uses: docker/setup-buildx-action@v3
+ uses: docker/setup-buildx-action@v4
- name: Build image (no push)
- uses: docker/build-push-action@v6
+ uses: docker/build-push-action@v7
with:
context: .
file: Dockerfile
@@ -402,7 +404,7 @@ jobs:
|| needs.build-docker.result == 'failure' || needs.build-docker.result == 'cancelled')
steps:
- name: Delete remote staging tag
- uses: actions/github-script@v8
+ uses: actions/github-script@v9
with:
script: |
const owner = context.repo.owner;
diff --git a/.github/workflows/tauri-cef-pin-guard.yml b/.github/workflows/tauri-cef-pin-guard.yml
index 0e1aa0789..7105dd835 100644
--- a/.github/workflows/tauri-cef-pin-guard.yml
+++ b/.github/workflows/tauri-cef-pin-guard.yml
@@ -27,7 +27,7 @@ jobs:
timeout-minutes: 5
steps:
- name: Checkout
- uses: actions/checkout@v5
+ uses: actions/checkout@v7
with:
persist-credentials: false
- name: Assert tauri-cef pin matches expected SHA
diff --git a/.github/workflows/test-reusable.yml b/.github/workflows/test-reusable.yml
index a29906d34..f1a4f18ae 100644
--- a/.github/workflows/test-reusable.yml
+++ b/.github/workflows/test-reusable.yml
@@ -53,12 +53,12 @@ jobs:
image: ghcr.io/tinyhumansai/openhuman_ci:rust-1.93.0
steps:
- name: Checkout code
- uses: actions/checkout@v5
+ uses: actions/checkout@v7
with:
ref: ${{ inputs.ref }}
fetch-depth: 1
- name: Cache pnpm store
- uses: actions/cache@v5
+ uses: actions/cache@v6
with:
path: ~/.local/share/pnpm/store
key: pnpm-store-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
@@ -78,7 +78,7 @@ jobs:
image: ghcr.io/tinyhumansai/openhuman_ci:rust-1.93.0
steps:
- name: Checkout code
- uses: actions/checkout@v5
+ uses: actions/checkout@v7
with:
ref: ${{ inputs.ref }}
fetch-depth: 1
@@ -88,9 +88,11 @@ jobs:
# `submodules: recursive`, which would also pull the large tauri-cef fork
# this job never builds.
- name: Init tinychannels submodule (drift-guard test reads its schemas)
- run: git submodule update --init vendor/tinychannels
+ run: |
+ git config --global --add safe.directory "$GITHUB_WORKSPACE"
+ git submodule update --init vendor/tinychannels
- name: Cache pnpm store
- uses: actions/cache@v5
+ uses: actions/cache@v6
with:
path: ~/.local/share/pnpm/store
key: pnpm-store-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
@@ -104,7 +106,7 @@ jobs:
NODE_ENV: test
- name: Upload coverage reports
if: always()
- uses: actions/upload-artifact@v5
+ uses: actions/upload-artifact@v7
with:
name: coverage-report
path: coverage
@@ -114,16 +116,29 @@ jobs:
if: inputs.run_rust_core
name: Rust Core Tests + Quality
runs-on: ubuntu-22.04
- timeout-minutes: 20
+ timeout-minutes: 60
container:
image: ghcr.io/tinyhumansai/openhuman_ci:rust-1.93.0
env:
CARGO_INCREMENTAL: "0"
- RUSTC_WRAPPER: sccache
- SCCACHE_GHA_ENABLED: "true"
+ # Keep the full core test binary link under hosted-runner memory/disk
+ # pressure. Tests do not need full DWARF; file/line backtraces remain.
+ CARGO_PROFILE_DEV_DEBUG: line-tables-only
+ CARGO_BUILD_JOBS: "1"
+ # Deep async agent-harness tests can overflow libtest's default ~2 MB
+ # per-test thread stack. Match ci-lite's core coverage stack setting.
+ RUST_MIN_STACK: "67108864"
steps:
+ - name: Free disk space
+ run: |
+ # Reclaim space on the build partition before compiling/linking the
+ # full Rust core test binary. The hosted toolcache is bind-mounted at
+ # /__t inside the container.
+ rm -rf /__t/* || true
+ df -h /__w || true
+
- name: Checkout code
- uses: actions/checkout@v5
+ uses: actions/checkout@v7
with:
ref: ${{ inputs.ref }}
fetch-depth: 1
@@ -135,8 +150,6 @@ jobs:
workspaces: . -> target
cache-on-failure: true
key: core
- - name: Install sccache
- uses: mozilla-actions/sccache-action@v0.0.9
- name: Test core crate (openhuman)
run: bash scripts/ci-cancel-aware.sh cargo test -p openhuman
@@ -144,14 +157,12 @@ jobs:
if: inputs.run_rust_core
name: Rust Core Tests (Windows — secrets ACL)
runs-on: windows-latest
- timeout-minutes: 30
+ timeout-minutes: 60
env:
- CARGO_INCREMENTAL: '0'
- SCCACHE_GHA_ENABLED: 'true'
- RUSTC_WRAPPER: sccache
+ CARGO_INCREMENTAL: "0"
steps:
- name: Checkout code
- uses: actions/checkout@v5
+ uses: actions/checkout@v7
with:
ref: ${{ inputs.ref }}
fetch-depth: 1
@@ -163,8 +174,6 @@ jobs:
workspaces: . -> target
cache-on-failure: true
key: core-windows
- - name: Install sccache
- uses: mozilla-actions/sccache-action@v0.0.9
- name: Run Windows-specific secrets tests
# Runs the keyring::encrypted_store suite (keyring::encrypted_store::tests),
# which contains the #[cfg(windows)] tests:
@@ -190,7 +199,7 @@ jobs:
SCCACHE_GHA_ENABLED: "true"
steps:
- name: Checkout code
- uses: actions/checkout@v5
+ uses: actions/checkout@v7
with:
ref: ${{ inputs.ref }}
fetch-depth: 1
@@ -206,13 +215,13 @@ jobs:
cache-on-failure: true
key: tauri
- name: Cache CEF binary distribution
- uses: actions/cache@v5
+ uses: actions/cache@v6
with:
path: ~/.cache/tauri-cef
key: cef-ubuntu-22.04-${{ hashFiles('app/src-tauri/Cargo.toml') }}
restore-keys: |
cef-ubuntu-22.04-
- name: Install sccache
- uses: mozilla-actions/sccache-action@v0.0.9
+ uses: mozilla-actions/sccache-action@v0.0.10
- name: Test Tauri shell (OpenHuman)
run: bash scripts/ci-cancel-aware.sh cargo test --manifest-path app/src-tauri/Cargo.toml
diff --git a/Cargo.lock b/Cargo.lock
index 0797052cc..2c5706f38 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2863,7 +2863,7 @@ dependencies = [
"js-sys",
"log",
"wasm-bindgen",
- "windows-core 0.62.2",
+ "windows-core 0.57.0",
]
[[package]]
@@ -4341,7 +4341,7 @@ dependencies = [
[[package]]
name = "openhuman"
-version = "0.58.12"
+version = "0.58.14"
dependencies = [
"aes-gcm",
"aho-corasick",
@@ -6928,7 +6928,7 @@ dependencies = [
[[package]]
name = "tinyplace"
-version = "2.0.0"
+version = "2.0.1"
dependencies = [
"aes",
"async-trait",
diff --git a/Cargo.toml b/Cargo.toml
index 3ba6fc8f5..8eb4a2195 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "openhuman"
-version = "0.58.12"
+version = "0.58.14"
edition = "2021"
description = "OpenHuman core business logic and RPC server"
autobins = false
diff --git a/app/package.json b/app/package.json
index d6335fbea..6e832d3db 100644
--- a/app/package.json
+++ b/app/package.json
@@ -1,6 +1,6 @@
{
"name": "openhuman-app",
- "version": "0.58.12",
+ "version": "0.58.14",
"type": "module",
"engines": {
"node": ">=24.0.0"
diff --git a/app/scripts/e2e-run-all-flows.sh b/app/scripts/e2e-run-all-flows.sh
index 9c1e676e5..ff473e248 100755
--- a/app/scripts/e2e-run-all-flows.sh
+++ b/app/scripts/e2e-run-all-flows.sh
@@ -8,8 +8,8 @@
# OPTIONS:
# --suite=SUITE Run only one suite category. Valid values:
# auth, navigation, chat, skills, notifications,
-# webhooks, providers, payments, settings, system,
-# journeys, all (default: all)
+# webhooks, providers, provider-web, payments, settings,
+# system, journeys, all (default: all)
# --bail Stop after the first spec failure (default: run all)
# --skip-preflight Skip the pre-flight environment check
#
@@ -57,7 +57,7 @@ for arg in "$@"; do
esac
done
-VALID_SUITES="auth navigation chat skills notifications webhooks providers connectors payments settings system journeys all"
+VALID_SUITES="auth navigation chat skills notifications webhooks providers provider-web connectors payments settings system journeys all"
# Accept comma-separated suite lists, e.g. --suite=auth,navigation,system.
# CI sharding passes one such list per matrix shard so a few parallel jobs
@@ -325,17 +325,28 @@ if should_run_suite "providers"; then
run "test/e2e/specs/telegram-channel-flow.spec.ts" "telegram-channel" "providers"
run "test/e2e/specs/gmail-flow.spec.ts" "gmail" "providers"
run "test/e2e/specs/accounts-provider-modal.spec.ts" "accounts-providers" "providers"
+ _mini_summary "providers"
+fi
+
+# Split browser-heavy provider flows out of the core provider shard. Telegram,
+# Gmail, and accounts already consume several minutes of Appium/CEF runtime on
+# Windows; keeping WhatsApp/conversations in the same shared session makes the
+# later specs prone to "session is either terminated or not started" teardown
+# failures before their own assertions run.
+if should_run_suite "provider-web"; then
+ echo ""
+ echo "## Running suite: provider-web"
# slack-flow currently crashes the CEF session mid-spec on Linux (#1850-style
# state issue); skip until investigated rather than nuke the rest of the
# provider suite.
- # run "test/e2e/specs/slack-flow.spec.ts" "slack" "providers"
- run "test/e2e/specs/whatsapp-flow.spec.ts" "whatsapp" "providers"
+ # run "test/e2e/specs/slack-flow.spec.ts" "slack" "provider-web"
+ run "test/e2e/specs/whatsapp-flow.spec.ts" "whatsapp" "provider-web"
# notion-flow.spec.ts was removed; skip to avoid "spec not found" failure.
- # run "test/e2e/specs/notion-flow.spec.ts" "notion" "providers"
- run "test/e2e/specs/conversations-web-channel-flow.spec.ts" "conversations" "providers"
- run "test/e2e/specs/composio-triggers-flow.spec.ts" "composio-triggers" "providers"
- run "test/e2e/specs/connectivity-state-differentiation.spec.ts" "connectivity-state" "providers"
- _mini_summary "providers"
+ # run "test/e2e/specs/notion-flow.spec.ts" "notion" "provider-web"
+ run "test/e2e/specs/conversations-web-channel-flow.spec.ts" "conversations" "provider-web"
+ run "test/e2e/specs/composio-triggers-flow.spec.ts" "composio-triggers" "provider-web"
+ run "test/e2e/specs/connectivity-state-differentiation.spec.ts" "connectivity-state" "provider-web"
+ _mini_summary "provider-web"
fi
# ---------------------------------------------------------------------------
diff --git a/app/src-tauri/Cargo.lock b/app/src-tauri/Cargo.lock
index 5d59126d9..24b462db9 100644
--- a/app/src-tauri/Cargo.lock
+++ b/app/src-tauri/Cargo.lock
@@ -4,7 +4,7 @@ version = 4
[[package]]
name = "OpenHuman"
-version = "0.58.12"
+version = "0.58.14"
dependencies = [
"anyhow",
"async-trait",
@@ -205,7 +205,7 @@ version = "1.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc"
dependencies = [
- "windows-sys 0.60.2",
+ "windows-sys 0.61.2",
]
[[package]]
@@ -216,7 +216,7 @@ checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d"
dependencies = [
"anstyle",
"once_cell_polyfill",
- "windows-sys 0.60.2",
+ "windows-sys 0.61.2",
]
[[package]]
@@ -250,7 +250,7 @@ dependencies = [
"objc2-foundation 0.3.2",
"parking_lot",
"percent-encoding",
- "windows-sys 0.60.2",
+ "windows-sys 0.59.0",
"x11rb",
]
@@ -2093,7 +2093,7 @@ dependencies = [
"libc",
"option-ext",
"redox_users 0.5.2",
- "windows-sys 0.60.2",
+ "windows-sys 0.59.0",
]
[[package]]
@@ -2496,7 +2496,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
dependencies = [
"libc",
- "windows-sys 0.60.2",
+ "windows-sys 0.59.0",
]
[[package]]
@@ -3737,7 +3737,7 @@ dependencies = [
"js-sys",
"log",
"wasm-bindgen",
- "windows-core 0.62.2",
+ "windows-core 0.57.0",
]
[[package]]
@@ -4136,7 +4136,7 @@ dependencies = [
"portable-atomic",
"portable-atomic-util",
"serde_core",
- "windows-sys 0.60.2",
+ "windows-sys 0.59.0",
]
[[package]]
@@ -5030,7 +5030,7 @@ version = "0.50.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
dependencies = [
- "windows-sys 0.60.2",
+ "windows-sys 0.59.0",
]
[[package]]
@@ -5570,7 +5570,7 @@ dependencies = [
[[package]]
name = "openhuman"
-version = "0.58.12"
+version = "0.58.14"
dependencies = [
"aes-gcm",
"aho-corasick",
@@ -6727,7 +6727,7 @@ dependencies = [
"once_cell",
"socket2",
"tracing",
- "windows-sys 0.60.2",
+ "windows-sys 0.59.0",
]
[[package]]
@@ -7314,7 +7314,7 @@ dependencies = [
"errno",
"libc",
"linux-raw-sys",
- "windows-sys 0.60.2",
+ "windows-sys 0.59.0",
]
[[package]]
@@ -7373,7 +7373,7 @@ dependencies = [
"security-framework 3.7.0",
"security-framework-sys",
"webpki-root-certs",
- "windows-sys 0.60.2",
+ "windows-sys 0.59.0",
]
[[package]]
@@ -8145,7 +8145,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e"
dependencies = [
"libc",
- "windows-sys 0.60.2",
+ "windows-sys 0.61.2",
]
[[package]]
@@ -8999,7 +8999,7 @@ dependencies = [
"getrandom 0.4.2",
"once_cell",
"rustix",
- "windows-sys 0.60.2",
+ "windows-sys 0.59.0",
]
[[package]]
@@ -9273,7 +9273,7 @@ dependencies = [
[[package]]
name = "tinyplace"
-version = "2.0.0"
+version = "2.0.1"
dependencies = [
"aes",
"async-trait",
@@ -9806,7 +9806,7 @@ checksum = "f2f6fb2847f6742cd76af783a2a2c49e9375d0a111c7bef6f71cd9e738c72d6e"
dependencies = [
"memoffset",
"tempfile",
- "windows-sys 0.60.2",
+ "windows-sys 0.61.2",
]
[[package]]
diff --git a/app/src-tauri/Cargo.toml b/app/src-tauri/Cargo.toml
index 7887fc879..12859c4c2 100644
--- a/app/src-tauri/Cargo.toml
+++ b/app/src-tauri/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "OpenHuman"
-version = "0.58.12"
+version = "0.58.14"
description = "OpenHuman - AI-powered Super Assistant"
authors = ["OpenHuman"]
edition = "2021"
diff --git a/app/src-tauri/tauri.conf.json b/app/src-tauri/tauri.conf.json
index de38616b6..d1388d16b 100644
--- a/app/src-tauri/tauri.conf.json
+++ b/app/src-tauri/tauri.conf.json
@@ -1,7 +1,7 @@
{
"$schema": "https://schema.tauri.app/config/2",
"productName": "OpenHuman",
- "version": "0.58.12",
+ "version": "0.58.14",
"identifier": "com.openhuman.app",
"build": {
"beforeDevCommand": "pnpm run dev",
diff --git a/app/src/components/intelligence/MemoryGraph.tsx b/app/src/components/intelligence/MemoryGraph.tsx
index 60221f2f4..e2d7a23a4 100644
--- a/app/src/components/intelligence/MemoryGraph.tsx
+++ b/app/src/components/intelligence/MemoryGraph.tsx
@@ -104,6 +104,16 @@ interface MemoryGraphProps {
mode: GraphMode;
/** Optional override for the empty-state message. */
emptyHint?: string;
+ /** Optional label for the central hub node (WebGL path). Defaults to "Memory". */
+ rootLabel?: string;
+ /** Fill the parent's height (full-screen) instead of the fixed 640px card. */
+ fill?: boolean;
+ /** Initial auto-fit zoom. Lower = more zoomed out. Defaults to 0.17. */
+ fitScale?: number;
+ /** Fit the whole graph tightly to the viewport instead of a fixed zoom. */
+ fitToBounds?: boolean;
+ /** Draw an always-on text label under each node. */
+ showLabels?: boolean;
/**
* Fired exactly once when the graph's force layout first settles (SVG
* worker `end`, the synchronous relax fallback, or the Pixi sim cooling).
@@ -195,7 +205,18 @@ function relaxLayout(nodes: SimNode[], edges: Array<[number, number]>, iteration
}
}
-export function MemoryGraph({ nodes, edges, mode, emptyHint, onReady }: MemoryGraphProps) {
+export function MemoryGraph({
+ nodes,
+ edges,
+ mode,
+ emptyHint,
+ rootLabel,
+ fill,
+ fitScale,
+ fitToBounds,
+ showLabels,
+ onReady,
+}: MemoryGraphProps) {
const { t } = useT();
const themeMode = useAppSelector(state => state.theme?.mode ?? 'system') as ThemeMode;
const isDark = resolveTheme(themeMode) === 'dark';
@@ -403,6 +424,7 @@ export function MemoryGraph({ nodes, edges, mode, emptyHint, onReady }: MemoryGr
// of re-rendering up to 10k elements through React every frame.
const circleEls = useRef<(SVGCircleElement | null)[]>([]);
const lineEls = useRef<(SVGLineElement | null)[]>([]);
+ const textEls = useRef<(SVGTextElement | null)[]>([]);
// Progressive DOM mount for the SVG path: reveal nodes in per-frame batches
// so a large graph never blocks building thousands of elements in one commit.
@@ -418,6 +440,7 @@ export function MemoryGraph({ nodes, edges, mode, emptyHint, onReady }: MemoryGr
simIdRef.current = sim;
circleEls.current = [];
lineEls.current = [];
+ textEls.current = [];
setSvgVisible(sim ? Math.min(sim.sim.length, FIRST_BATCH) : 0);
}
@@ -438,6 +461,11 @@ export function MemoryGraph({ nodes, edges, mode, emptyHint, onReady }: MemoryGr
el.setAttribute('cx', String(ns[i].x));
el.setAttribute('cy', String(ns[i].y));
}
+ const tel = textEls.current[i];
+ if (tel) {
+ tel.setAttribute('x', String(ns[i].x));
+ tel.setAttribute('y', String(ns[i].y + nodeRadius(ns[i]) + 12));
+ }
}
for (let e = 0; e < s.edges.length; e++) {
const [ai, bi] = s.edges[e];
@@ -462,12 +490,35 @@ export function MemoryGraph({ nodes, edges, mode, emptyHint, onReady }: MemoryGr
const ns = s.sim;
if (ns.length === 0) return;
// Center on the root node at a fixed comfortable zoom.
+ if (fitToBounds) {
+ let minX = Infinity;
+ let minY = Infinity;
+ let maxX = -Infinity;
+ let maxY = -Infinity;
+ for (const n of ns) {
+ const r = nodeRadius(n) + 8;
+ minX = Math.min(minX, n.x - r);
+ minY = Math.min(minY, n.y - r);
+ maxX = Math.max(maxX, n.x + r);
+ maxY = Math.max(maxY, n.y + r);
+ }
+ const w = Math.max(1, maxX - minX);
+ const h = Math.max(1, maxY - minY);
+ const scale = Math.min(
+ ZOOM_MAX,
+ Math.max(ZOOM_MIN, Math.min(VIEWPORT_W / w, VIEWPORT_H / h) * 0.92)
+ );
+ const bx = (minX + maxX) / 2;
+ const by = (minY + maxY) / 2;
+ setView({ scale, tx: VIEWPORT_W / 2 - bx * scale, ty: VIEWPORT_H / 2 - by * scale });
+ return;
+ }
const root = ns.find(n => n.kind === 'root');
const cx = root?.x ?? 0;
const cy = root?.y ?? 0;
- const scale = 0.17;
+ const scale = fitScale ?? 0.17;
setView({ scale, tx: VIEWPORT_W / 2 - cx * scale, ty: VIEWPORT_H / 2 - cy * scale });
- }, []);
+ }, [fitScale, fitToBounds]);
fitRef.current = fitToView;
// Coalesce worker ticks to one DOM write per frame.
@@ -565,9 +616,11 @@ export function MemoryGraph({ nodes, edges, mode, emptyHint, onReady }: MemoryGr
return (
setHovered(null)}>
-
+
{nodes.length} {t('graph.nodes')}
@@ -606,6 +659,11 @@ export function MemoryGraph({ nodes, edges, mode, emptyHint, onReady }: MemoryGr
nodes={nodes}
edges={edges}
mode={mode}
+ rootLabel={rootLabel}
+ fill={fill}
+ fitScale={fitScale}
+ fitToBounds={fitToBounds}
+ showLabels={showLabels}
dark={
typeof document !== 'undefined' && document.documentElement.classList.contains('dark')
}
@@ -621,9 +679,9 @@ export function MemoryGraph({ nodes, edges, mode, emptyHint, onReady }: MemoryGr
)}
diff --git a/app/src/components/intelligence/PixiGraph.tsx b/app/src/components/intelligence/PixiGraph.tsx
index 2322b7cce..f3d9fcdc3 100644
--- a/app/src/components/intelligence/PixiGraph.tsx
+++ b/app/src/components/intelligence/PixiGraph.tsx
@@ -17,6 +17,16 @@ interface PixiGraphProps {
edges: GraphEdge[];
mode: GraphMode;
dark: boolean;
+ /** Optional label for the synthetic hub node (defaults to "Memory"). */
+ rootLabel?: string;
+ /** Fill the parent's height instead of the fixed 640px cap. */
+ fill?: boolean;
+ /** Initial auto-fit zoom (world scale). Defaults to 0.17. */
+ fitScale?: number;
+ /** Fit the whole node cloud tightly to the viewport instead of a fixed zoom. */
+ fitToBounds?: boolean;
+ /** Draw an always-on text label under each node. */
+ showLabels?: boolean;
/** Bump to recentre the view (Reset view button). */
resetSignal: number;
onHover: (node: GraphNode | null) => void;
@@ -33,6 +43,11 @@ export function PixiGraph({
edges,
mode,
dark,
+ rootLabel,
+ fill,
+ fitScale,
+ fitToBounds,
+ showLabels,
resetSignal,
onHover,
onOpen,
@@ -61,7 +76,7 @@ export function PixiGraph({
// Mode change requires full remount (different edge semantics).
if (handleRef.current && mountedModeRef.current === mode) {
- const { simNodes, links } = buildGraph(nodes, edges, mode);
+ const { simNodes, links } = buildGraph(nodes, edges, mode, rootLabel);
handleRef.current.updateGraph(simNodes, links);
return;
}
@@ -70,11 +85,14 @@ export function PixiGraph({
let cancelled = false;
handleRef.current?.destroy();
handleRef.current = null;
- const { simNodes, links } = buildGraph(nodes, edges, mode);
+ const { simNodes, links } = buildGraph(nodes, edges, mode, rootLabel);
const pending = mountPixiGraph(host, {
simNodes,
links,
dark: darkRef.current,
+ fitScale,
+ fitToBounds,
+ showLabels,
onHover: n => onHoverRef.current(n),
onOpen: n => onOpenRef.current(n),
onReady: () => onReadyRef.current?.(),
@@ -99,7 +117,7 @@ export function PixiGraph({
mountedModeRef.current = null;
void pending.then(handle => handle?.destroy());
};
- }, [nodes, edges, mode]);
+ }, [nodes, edges, mode, rootLabel, fitScale, fitToBounds, showLabels]);
useEffect(() => {
handleRef.current?.setTheme(dark);
@@ -113,8 +131,8 @@ export function PixiGraph({
);
}
diff --git a/app/src/components/intelligence/memoryGraphLayout.ts b/app/src/components/intelligence/memoryGraphLayout.ts
index 5586d8386..692977751 100644
--- a/app/src/components/intelligence/memoryGraphLayout.ts
+++ b/app/src/components/intelligence/memoryGraphLayout.ts
@@ -57,6 +57,7 @@ export function levelColor(level: number | null | undefined): string {
}
export function nodeColor(node: GraphNode): string {
+ if (node.color) return node.color; // UI override (e.g. dimmed offline agents)
if (node.kind === 'root') return ROOT_COLOR;
if (node.kind === 'source') return SOURCE_COLOR;
if (node.kind === 'summary') return levelColor(node.level);
@@ -104,12 +105,15 @@ export const ROOT_NODE_ID = '__root__';
export function buildGraph(
nodes: GraphNode[],
edges: GraphEdge[],
- mode: GraphMode
+ mode: GraphMode,
+ rootLabel = 'Memory'
): { simNodes: SimNode[]; links: SimLink[] } {
const ids = new Set(nodes.map(n => n.id));
// Synthetic master root at the origin — all source nodes fan out from it.
- const rootNode: SimNode = { kind: 'root', id: ROOT_NODE_ID, label: 'Memory', x: 0, y: 0 };
+ // `rootLabel` lets non-memory reuses (e.g. the orchestration overview) name
+ // the hub; defaults to "Memory".
+ const rootNode: SimNode = { kind: 'root', id: ROOT_NODE_ID, label: rootLabel, x: 0, y: 0 };
const simNodes: SimNode[] = [rootNode];
for (let i = 0; i < nodes.length; i++) {
diff --git a/app/src/components/intelligence/pixiGraphRenderer.ts b/app/src/components/intelligence/pixiGraphRenderer.ts
index fda5b955b..82265260b 100644
--- a/app/src/components/intelligence/pixiGraphRenderer.ts
+++ b/app/src/components/intelligence/pixiGraphRenderer.ts
@@ -13,7 +13,7 @@
* Drawing is dirty-flagged: while the simulation is warm (or the user is
* interacting) we redraw each frame; once it cools the loop idles.
*/
-import { Application, Container, type FederatedPointerEvent, Graphics } from 'pixi.js';
+import { Application, Container, type FederatedPointerEvent, Graphics, Text } from 'pixi.js';
import 'pixi.js/unsafe-eval';
import {
@@ -36,6 +36,12 @@ export interface PixiGraphOptions {
onOpen: (node: SimNode) => void;
/** Fired once the force simulation first cools (graph is laid out). */
onReady?: () => void;
+ /** Initial auto-fit zoom (world scale). Defaults to 0.17. */
+ fitScale?: number;
+ /** Fit the whole node cloud tightly to the viewport instead of a fixed zoom. */
+ fitToBounds?: boolean;
+ /** Draw an always-on text label under each node (off by default). */
+ showLabels?: boolean;
}
export interface PixiGraphHandle {
@@ -76,8 +82,10 @@ export async function mountPixiGraph(
const world = new Container();
const edgeG = new Graphics();
const nodeG = new Graphics();
+ const labelG = new Container();
world.addChild(edgeG);
world.addChild(nodeG);
+ world.addChild(labelG); // labels paint above the discs
app.stage.addChild(world);
const recenter = () => world.position.set(app.screen.width / 2, app.screen.height / 2);
@@ -96,17 +104,74 @@ export async function mountPixiGraph(
// so the initial frame is zoomed out to show as much as possible.
let userInteracted = false;
- /** Centre on the root node at a fixed comfortable zoom. */
+ /**
+ * Frame the graph. With `fitToBounds`, scale so the whole node cloud fits the
+ * viewport as tightly as possible (a little margin for node radii/labels);
+ * otherwise centre on the root at a fixed comfortable zoom (`fitScale`).
+ */
const fitToView = () => {
if (opts.simNodes.length === 0) return;
+
+ if (opts.fitToBounds) {
+ let minX = Infinity;
+ let minY = Infinity;
+ let maxX = -Infinity;
+ let maxY = -Infinity;
+ for (const n of opts.simNodes) {
+ const r = nodeRadius(n) + 8; // pad for the node radius + a little label room
+ minX = Math.min(minX, n.x - r);
+ minY = Math.min(minY, n.y - r);
+ maxX = Math.max(maxX, n.x + r);
+ maxY = Math.max(maxY, n.y + r);
+ }
+ const w = Math.max(1, maxX - minX);
+ const h = Math.max(1, maxY - minY);
+ const margin = 0.92; // leave ~8% breathing room around the content
+ const scale = Math.min(
+ ZOOM_MAX,
+ Math.max(ZOOM_MIN, Math.min(app.screen.width / w, app.screen.height / h) * margin)
+ );
+ const cx = (minX + maxX) / 2;
+ const cy = (minY + maxY) / 2;
+ world.scale.set(scale);
+ world.position.set(app.screen.width / 2 - cx * scale, app.screen.height / 2 - cy * scale);
+ return;
+ }
+
const root = opts.simNodes.find(n => n.kind === 'root');
const cx = root?.x ?? 0;
const cy = root?.y ?? 0;
- const scale = 0.17;
+ const scale = opts.fitScale ?? 0.17;
world.scale.set(scale);
world.position.set(app.screen.width / 2 - cx * scale, app.screen.height / 2 - cy * scale);
};
+ // Always-on node labels (opt-in via `showLabels`). Parallel to `opts.simNodes`
+ // and repositioned each frame in `draw()` so they track the simulation.
+ const labelColor = () => (dark ? 0xe2e8f0 : 0x334155);
+ const labelText = (n: SimNode): string => {
+ const s = (n.label ?? '').trim();
+ return s.length > 22 ? `${s.slice(0, 21)}…` : s;
+ };
+ let labels: Text[] = [];
+ const rebuildLabels = () => {
+ for (const label of labels) label.destroy();
+ labels = [];
+ labelG.removeChildren();
+ if (!opts.showLabels) return;
+ for (const n of opts.simNodes) {
+ const text = new Text({
+ text: labelText(n),
+ style: { fontFamily: 'sans-serif', fontSize: 13, fill: labelColor(), align: 'center' },
+ });
+ text.anchor.set(0.5, 0);
+ text.resolution = 2; // crisp when the world is scaled up
+ labelG.addChild(text);
+ labels.push(text);
+ }
+ };
+ rebuildLabels();
+
const draw = () => {
edgeG.clear();
for (const l of opts.links) {
@@ -132,6 +197,18 @@ export async function mountPixiGraph(
nodeG.circle(n.x, n.y, r).fill({ color: colorNum(nodeColor(n)), alpha: 1 });
if (hover) nodeG.circle(n.x, n.y, r).stroke({ width: 1.4, color: 0x0f172a, alpha: 0.9 });
}
+
+ // Node labels follow the discs; recolour to the live theme.
+ if (opts.showLabels) {
+ const fill = labelColor();
+ for (let i = 0; i < labels.length; i++) {
+ const n = opts.simNodes[i];
+ const label = labels[i];
+ if (!n || !label) continue;
+ label.position.set(n.x, n.y + nodeRadius(n) + 3);
+ label.style.fill = fill;
+ }
+ }
};
app.ticker.add(() => {
@@ -296,6 +373,7 @@ export async function mountPixiGraph(
// Hot-swap the simulation's node and link arrays.
opts.simNodes = nextNodes;
opts.links = nextLinks;
+ rebuildLabels();
sim.nodes(nextNodes);
const linkForce = sim.force('link') as ReturnType;
if (linkForce && typeof linkForce.links === 'function') {
diff --git a/app/src/components/layout/TwoPaneNav.tsx b/app/src/components/layout/TwoPaneNav.tsx
index e37e78327..fe4be8cd1 100644
--- a/app/src/components/layout/TwoPaneNav.tsx
+++ b/app/src/components/layout/TwoPaneNav.tsx
@@ -18,6 +18,11 @@ interface TwoPaneNavProps {
onSelect: (value: string) => void;
/** Optional fixed header (title/subtitle) above the scrolling nav list. */
header?: ReactNode;
+ /**
+ * Optional content rendered inside the scroll region *below* the nav groups —
+ * e.g. a separator + a live list of active sessions. Scrolls with the nav.
+ */
+ footer?: ReactNode;
ariaLabel?: string;
}
@@ -33,12 +38,15 @@ export default function TwoPaneNav({
selected,
onSelect,
header,
+ footer,
ariaLabel,
}: TwoPaneNavProps) {
return (