feat(local-chat): add local conversation with file attachment support #473
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Desktop CI Dist Full | |
| on: | |
| pull_request: | |
| paths: | |
| - "apps/desktop/**" | |
| - "packages/slimclaw/**" | |
| - "pnpm-lock.yaml" | |
| - "scripts/desktop-check-dist.sh" | |
| - "scripts/desktop-verify-extracted-runner.sh" | |
| - "scripts/desktop-ci-check.mjs" | |
| - "scripts/postinstall.mjs" | |
| - ".github/workflows/desktop-ci-dist-full.yml" | |
| push: | |
| branches: | |
| - main | |
| paths: | |
| - "apps/desktop/**" | |
| - "packages/slimclaw/**" | |
| - "pnpm-lock.yaml" | |
| - "scripts/desktop-check-dist.sh" | |
| - "scripts/desktop-verify-extracted-runner.sh" | |
| - "scripts/desktop-ci-check.mjs" | |
| - "scripts/postinstall.mjs" | |
| - ".github/workflows/desktop-ci-dist-full.yml" | |
| workflow_dispatch: | |
| inputs: | |
| auto_update_enabled: | |
| description: "Enable auto-update in CI build artifacts" | |
| required: false | |
| default: "false" | |
| type: choice | |
| options: | |
| - "false" | |
| - "true" | |
| permissions: | |
| contents: read | |
| concurrency: | |
| group: desktop-ci-dist-full-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| prepare-runtime: | |
| runs-on: macos-14 | |
| timeout-minutes: 45 | |
| env: | |
| LANGFUSE_PUBLIC_KEY: ${{ secrets.LANGFUSE_PUBLIC_KEY }} | |
| LANGFUSE_SECRET_KEY: ${{ secrets.LANGFUSE_SECRET_KEY }} | |
| LANGFUSE_BASE_URL: ${{ secrets.LANGFUSE_BASE_URL }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@v4 | |
| with: | |
| version: 10.26.0 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: 24 | |
| cache: pnpm | |
| cache-dependency-path: pnpm-lock.yaml | |
| - name: Restore npm cache for runtime installs | |
| uses: actions/cache@v4 | |
| with: | |
| path: ~/.npm | |
| key: desktop-npm-cache-${{ runner.os }}-arm64-${{ hashFiles('packages/slimclaw/runtime-seed/package-lock.json', 'apps/controller/static/runtime-plugins/openclaw-weixin/package-lock.json') }} | |
| restore-keys: | | |
| desktop-npm-cache-${{ runner.os }}-arm64- | |
| desktop-npm-cache-${{ runner.os }}- | |
| - name: Restore Electron build caches | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/Library/Caches/electron | |
| ~/Library/Caches/electron-builder | |
| apps/desktop/.cache | |
| key: desktop-electron-cache-${{ runner.os }}-arm64-${{ hashFiles('pnpm-lock.yaml', 'apps/desktop/package.json') }} | |
| restore-keys: | | |
| desktop-electron-cache-${{ runner.os }}-arm64- | |
| desktop-electron-cache-${{ runner.os }}- | |
| - name: Install dependencies | |
| run: pnpm install --frozen-lockfile | |
| - name: Show desktop toolchain versions | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| pnpm exec electron --version | |
| - name: Build all (shared prepare) | |
| run: pnpm build | |
| - name: Upload shared desktop prepare artifacts | |
| if: success() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: desktop-ci-heavy-prepare-builds | |
| path: | | |
| packages/shared/dist/** | |
| apps/controller/dist/** | |
| apps/controller/.dist-runtime/plugins/** | |
| apps/web/dist/** | |
| apps/desktop/dist/** | |
| apps/desktop/dist-electron/** | |
| if-no-files-found: error | |
| retention-days: 3 | |
| package: | |
| needs: prepare-runtime | |
| strategy: | |
| matrix: | |
| include: | |
| - runner: macos-14 | |
| arch: arm64 | |
| - runner: macos-15-intel | |
| arch: x64 | |
| runs-on: ${{ matrix.runner }} | |
| timeout-minutes: 45 | |
| env: | |
| NEXU_DESKTOP_MAC_TARGETS: dmg zip | |
| LANGFUSE_PUBLIC_KEY: ${{ secrets.LANGFUSE_PUBLIC_KEY }} | |
| LANGFUSE_SECRET_KEY: ${{ secrets.LANGFUSE_SECRET_KEY }} | |
| LANGFUSE_BASE_URL: ${{ secrets.LANGFUSE_BASE_URL }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@v4 | |
| with: | |
| version: 10.26.0 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: 24 | |
| cache: pnpm | |
| cache-dependency-path: pnpm-lock.yaml | |
| - name: Restore npm cache for runtime installs | |
| uses: actions/cache@v4 | |
| with: | |
| path: ~/.npm | |
| key: desktop-npm-cache-${{ runner.os }}-${{ matrix.arch }}-${{ hashFiles('packages/slimclaw/runtime-seed/package-lock.json', 'apps/controller/static/runtime-plugins/openclaw-weixin/package-lock.json') }} | |
| restore-keys: | | |
| desktop-npm-cache-${{ runner.os }}-${{ matrix.arch }}- | |
| desktop-npm-cache-${{ runner.os }}- | |
| - name: Restore Electron build caches | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/Library/Caches/electron | |
| ~/Library/Caches/electron-builder | |
| apps/desktop/.cache | |
| key: desktop-electron-cache-${{ runner.os }}-${{ matrix.arch }}-${{ hashFiles('pnpm-lock.yaml', 'apps/desktop/package.json') }} | |
| restore-keys: | | |
| desktop-electron-cache-${{ runner.os }}-${{ matrix.arch }}- | |
| desktop-electron-cache-${{ runner.os }}- | |
| - name: Install dependencies | |
| run: pnpm install --frozen-lockfile | |
| - name: Download shared desktop prepare artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: desktop-ci-heavy-prepare-builds | |
| path: ${{ github.workspace }} | |
| - name: Build unsigned macOS desktop bundle | |
| env: | |
| NEXU_DESKTOP_TARGET_ARCH: ${{ matrix.arch }} | |
| NEXU_DESKTOP_USE_EXISTING_BUILDS: "1" | |
| NEXU_DESKTOP_USE_EXISTING_RUNTIME_INSTALL: "1" | |
| NEXU_DESKTOP_AUTO_UPDATE_ENABLED: ${{ github.event_name == 'workflow_dispatch' && inputs.auto_update_enabled || 'false' }} | |
| run: pnpm dist:mac:unsigned | |
| - name: Set packaged app paths | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| shopt -s nullglob | |
| runner_home="$HOME" | |
| packaged_home="$RUNNER_TEMP/desktop-home" | |
| packaged_user_data_dir="$packaged_home/Library/Application Support/@nexu/desktop" | |
| packaged_logs_dir="$packaged_user_data_dir/logs" | |
| packaged_runtime_logs_dir="$packaged_logs_dir/runtime-units" | |
| default_user_data_dir="$runner_home/Library/Application Support/@nexu/desktop" | |
| default_logs_dir="$default_user_data_dir/logs" | |
| default_runtime_logs_dir="$default_logs_dir/runtime-units" | |
| packaged_apps=(apps/desktop/release/mac*/Nexu.app) | |
| if [ "${#packaged_apps[@]}" -eq 0 ]; then | |
| echo "No packaged app bundle found under apps/desktop/release/mac*" >&2 | |
| exit 1 | |
| fi | |
| packaged_app="${packaged_apps[0]}" | |
| packaged_executable="$packaged_app/Contents/MacOS/Nexu" | |
| mkdir -p "$RUNNER_TEMP/desktop-ci" "$packaged_home" "$RUNNER_TEMP/desktop-tmp" | |
| { | |
| echo "PACKAGED_HOME=$packaged_home" | |
| echo "PACKAGED_LOGS_DIR=$packaged_logs_dir" | |
| echo "PACKAGED_USER_DATA_DIR=$packaged_user_data_dir" | |
| echo "PACKAGED_RUNTIME_LOGS_DIR=$packaged_runtime_logs_dir" | |
| echo "DEFAULT_LOGS_DIR=$default_logs_dir" | |
| echo "DEFAULT_USER_DATA_DIR=$default_user_data_dir" | |
| echo "DEFAULT_RUNTIME_LOGS_DIR=$default_runtime_logs_dir" | |
| echo "PACKAGED_APP=$packaged_app" | |
| echo "PACKAGED_EXECUTABLE=$packaged_executable" | |
| } >> "$GITHUB_ENV" | |
| - name: Verify packaged desktop artifacts | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| shopt -s nullglob | |
| dmg_artifacts=(apps/desktop/release/*.dmg) | |
| zip_artifacts=(apps/desktop/release/*.zip) | |
| if [ "${#dmg_artifacts[@]}" -eq 0 ]; then | |
| echo "No desktop DMG artifact was produced" >&2 | |
| exit 1 | |
| fi | |
| if [ "${#zip_artifacts[@]}" -eq 0 ]; then | |
| echo "No desktop ZIP artifact was produced" >&2 | |
| exit 1 | |
| fi | |
| printf 'Built artifacts:\n' | |
| printf ' - %s\n' "${dmg_artifacts[@]}" | |
| printf ' - %s\n' "${zip_artifacts[@]}" | |
| test -d "$PACKAGED_APP" | |
| test -x "$PACKAGED_EXECUTABLE" | |
| - name: Upload desktop build artifacts | |
| if: success() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: desktop-ci-dist-${{ matrix.arch }} | |
| path: | | |
| apps/desktop/release/*.dmg | |
| apps/desktop/release/*.zip | |
| if-no-files-found: error | |
| retention-days: 3 | |
| - name: Verify packaged runtime unit health | |
| env: | |
| NEXU_DESKTOP_CHECK_CAPTURE_DIR: ${{ runner.temp }}/desktop-ci | |
| NEXU_DESKTOP_CHECK_TMPDIR: ${{ runner.temp }}/desktop-tmp | |
| run: pnpm check:dist | |
| - name: Verify extracted runner bundle integrity | |
| env: | |
| NEXU_DESKTOP_CHECK_TMPDIR: ${{ runner.temp }}/desktop-tmp | |
| NEXU_DESKTOP_REQUIRE_SPCTL: "0" | |
| run: bash scripts/desktop-verify-extracted-runner.sh | |
| - name: Capture desktop logs | |
| if: always() | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| mkdir -p "$RUNNER_TEMP/desktop-ci" | |
| if [ -n "${PACKAGED_LOGS_DIR:-}" ] && [ -d "$PACKAGED_LOGS_DIR" ]; then | |
| cp -R "$PACKAGED_LOGS_DIR" "$RUNNER_TEMP/desktop-ci/packaged-logs" | |
| fi | |
| if [ -n "${PACKAGED_RUNTIME_LOGS_DIR:-}" ] && [ -d "$PACKAGED_RUNTIME_LOGS_DIR" ]; then | |
| cp -R "$PACKAGED_RUNTIME_LOGS_DIR" "$RUNNER_TEMP/desktop-ci/runtime-unit-logs" | |
| fi | |
| if [ -n "${DEFAULT_LOGS_DIR:-}" ] && [ -d "$DEFAULT_LOGS_DIR" ]; then | |
| cp -R "$DEFAULT_LOGS_DIR" "$RUNNER_TEMP/desktop-ci/default-logs" | |
| fi | |
| if [ -n "${DEFAULT_RUNTIME_LOGS_DIR:-}" ] && [ -d "$DEFAULT_RUNTIME_LOGS_DIR" ]; then | |
| cp -R "$DEFAULT_RUNTIME_LOGS_DIR" "$RUNNER_TEMP/desktop-ci/default-runtime-unit-logs" | |
| fi | |
| - name: Upload desktop logs | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: desktop-ci-logs-${{ matrix.arch }} | |
| path: ${{ runner.temp }}/desktop-ci | |
| if-no-files-found: warn | |
| retention-days: 3 | |
| package-windows: | |
| runs-on: windows-latest | |
| timeout-minutes: 45 | |
| env: | |
| LANGFUSE_PUBLIC_KEY: ${{ secrets.LANGFUSE_PUBLIC_KEY }} | |
| LANGFUSE_SECRET_KEY: ${{ secrets.LANGFUSE_SECRET_KEY }} | |
| LANGFUSE_BASE_URL: ${{ secrets.LANGFUSE_BASE_URL }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@v4 | |
| with: | |
| version: 10.26.0 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: 24 | |
| cache: pnpm | |
| cache-dependency-path: pnpm-lock.yaml | |
| - name: Restore npm cache for runtime installs | |
| uses: actions/cache@v4 | |
| with: | |
| path: ~\AppData\Local\npm-cache | |
| key: desktop-npm-cache-${{ runner.os }}-x64-${{ hashFiles('packages/slimclaw/runtime-seed/package-lock.json', 'apps/controller/static/runtime-plugins/openclaw-weixin/package-lock.json') }} | |
| restore-keys: | | |
| desktop-npm-cache-${{ runner.os }}-x64- | |
| desktop-npm-cache-${{ runner.os }}- | |
| - name: Restore Electron build caches | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~\AppData\Local\electron\Cache | |
| ~\AppData\Local\electron-builder\Cache | |
| apps/desktop/.cache | |
| key: desktop-electron-cache-${{ runner.os }}-x64-${{ hashFiles('pnpm-lock.yaml', 'apps/desktop/package.json') }} | |
| restore-keys: | | |
| desktop-electron-cache-${{ runner.os }}-x64- | |
| desktop-electron-cache-${{ runner.os }}- | |
| - name: Install dependencies | |
| run: pnpm install --frozen-lockfile | |
| - name: Install Windows packaging tools | |
| shell: pwsh | |
| run: | | |
| choco install nsis -y --no-progress | |
| - name: Show desktop toolchain versions | |
| shell: pwsh | |
| run: pnpm exec electron --version | |
| - name: Build workspace artifacts | |
| run: pnpm build | |
| - name: Build unsigned Windows desktop bundle | |
| env: | |
| NEXU_DESKTOP_AUTO_UPDATE_ENABLED: ${{ github.event_name == 'workflow_dispatch' && inputs.auto_update_enabled || 'false' }} | |
| run: pnpm --filter @nexu/desktop dist:win | |
| - name: Verify packaged Windows artifacts | |
| shell: pwsh | |
| run: | | |
| $releaseDir = Join-Path $PWD "apps/desktop/release" | |
| $installerArtifacts = Get-ChildItem -Path $releaseDir -Filter "*.exe" -File | |
| if ($installerArtifacts.Count -eq 0) { | |
| Write-Error "No Windows installer artifact was produced" | |
| } | |
| $unpackedExecutable = Join-Path $releaseDir "win-unpacked/Nexu.exe" | |
| if (-not (Test-Path $unpackedExecutable)) { | |
| Write-Error "Missing unpacked Windows app executable: $unpackedExecutable" | |
| } | |
| $openclawRuntimeRoot = Join-Path $PWD "apps/desktop/.dist-runtime/openclaw" | |
| $archiveMetadata = Join-Path $openclawRuntimeRoot "archive.json" | |
| $unarchivedPackageJson = Join-Path $openclawRuntimeRoot "package.json" | |
| $unarchivedNodeModules = Join-Path $openclawRuntimeRoot "node_modules" | |
| if (-not (Test-Path $openclawRuntimeRoot)) { | |
| Write-Error "Missing OpenClaw runtime root: $openclawRuntimeRoot" | |
| } | |
| if (-not (Test-Path $archiveMetadata) -and ((-not (Test-Path $unarchivedPackageJson)) -or (-not (Test-Path $unarchivedNodeModules)))) { | |
| Write-Error "Missing OpenClaw runtime payload metadata under: $openclawRuntimeRoot" | |
| } | |
| Write-Host "Built Windows artifacts:" | |
| $installerArtifacts | ForEach-Object { Write-Host " - $($_.FullName)" } | |
| Write-Host " - $unpackedExecutable" | |
| if (Test-Path $archiveMetadata) { | |
| Write-Host " - $archiveMetadata" | |
| } else { | |
| Write-Host " - $unarchivedPackageJson" | |
| Write-Host " - $unarchivedNodeModules" | |
| } | |
| - name: Upload Windows build artifacts | |
| if: success() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: desktop-ci-dist-win-x64 | |
| path: | | |
| apps/desktop/release/*.exe | |
| apps/desktop/release/win-unpacked/** | |
| if-no-files-found: error | |
| retention-days: 3 | |
| - name: Capture Windows build logs | |
| if: always() | |
| shell: pwsh | |
| run: | | |
| $captureDir = Join-Path $env:RUNNER_TEMP "desktop-ci-win" | |
| New-Item -ItemType Directory -Force -Path $captureDir | Out-Null | |
| if (Test-Path "apps/desktop/.dist-runtime") { | |
| Copy-Item "apps/desktop/.dist-runtime" (Join-Path $captureDir "dist-runtime") -Recurse -Force | |
| } | |
| if (Test-Path ".tmp") { | |
| Copy-Item ".tmp" (Join-Path $captureDir "repo-tmp") -Recurse -Force | |
| } | |
| - name: Upload Windows build logs | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: desktop-ci-logs-win-x64 | |
| path: ${{ runner.temp }}/desktop-ci-win | |
| if-no-files-found: warn | |
| retention-days: 3 |