feat(deploy): refactor XWorkmate and OpenClaw deployments to use offline GitHub Release tarballs

This commit is contained in:
Haitao Pan 2026-06-19 19:50:06 +08:00
parent 6aa240c16b
commit cdbfb2e92a
6 changed files with 101 additions and 120 deletions

View File

@ -38,10 +38,21 @@
changed_when: true
become: true
- name: Upload XWorkmate Go ACP server binary
ansible.builtin.copy:
src: "{{ acp_codex_bridge_local_binary_path }}"
dest: "{{ acp_codex_bridge_binary_path }}"
- name: Download XWorkmate Bridge release archive
ansible.builtin.get_url:
url: "https://github.com/ai-workspace-lab/xworkmate-bridge/releases/latest/download/xworkmate-bridge-{{ ansible_system | lower }}-{{ 'amd64' if ansible_architecture in ['x86_64', 'amd64'] else 'arm64' }}.tar.gz"
dest: "/tmp/xworkmate-bridge.tar.gz"
mode: "0644"
when: not (acp_codex_bridge_use_prebuilt | bool)
- name: Extract XWorkmate Go ACP server binary
ansible.builtin.unarchive:
src: "/tmp/xworkmate-bridge.tar.gz"
dest: "{{ acp_codex_bridge_binary_path | dirname }}"
remote_src: true
extra_opts:
- "--strip-components=2"
- "xworkmate-bridge/bin/xworkmate-go-core"
owner: root
group: root
mode: "0755"

View File

@ -38,16 +38,27 @@
changed_when: true
become: true
- name: Upload XWorkmate Go ACP adapter binary for Gemini
ansible.builtin.copy:
src: "{{ acp_gemini_bridge_local_binary_path }}"
dest: "{{ acp_gemini_bridge_binary_path }}"
- name: Download XWorkmate Bridge release archive for Gemini
ansible.builtin.get_url:
url: "https://github.com/ai-workspace-lab/xworkmate-bridge/releases/latest/download/xworkmate-bridge-{{ ansible_system | lower }}-{{ 'amd64' if ansible_architecture in ['x86_64', 'amd64'] else 'arm64' }}.tar.gz"
dest: "/tmp/xworkmate-bridge-gemini.tar.gz"
mode: "0644"
when: not (acp_gemini_bridge_use_prebuilt | bool)
- name: Extract XWorkmate Go ACP adapter binary for Gemini
ansible.builtin.unarchive:
src: "/tmp/xworkmate-bridge-gemini.tar.gz"
dest: "{{ acp_gemini_bridge_binary_path | dirname }}"
remote_src: true
extra_opts:
- "--strip-components=2"
- "xworkmate-bridge/bin/xworkmate-go-core"
owner: "{{ omit if ansible_os_family == 'Darwin' else acp_gemini_service_user }}"
group: "{{ omit if ansible_os_family == 'Darwin' else acp_gemini_service_group }}"
mode: "0755"
notify: Restart acp gemini
when: not (acp_gemini_bridge_use_prebuilt | bool)
become: true
when: not (acp_gemini_bridge_use_prebuilt | bool)
- name: Restore immutable flag on Gemini bridge binary
ansible.builtin.command:

View File

@ -37,10 +37,21 @@
changed_when: true
become: true
- name: Upload XWorkmate Go ACP server binary for OpenCode
ansible.builtin.copy:
src: "{{ acp_opencode_bridge_local_binary_path }}"
dest: "{{ acp_opencode_bridge_binary_path }}"
- name: Download XWorkmate Bridge release archive for OpenCode
ansible.builtin.get_url:
url: "https://github.com/ai-workspace-lab/xworkmate-bridge/releases/latest/download/xworkmate-bridge-{{ ansible_system | lower }}-{{ 'amd64' if ansible_architecture in ['x86_64', 'amd64'] else 'arm64' }}.tar.gz"
dest: "/tmp/xworkmate-bridge-opencode.tar.gz"
mode: "0644"
when: not (acp_opencode_bridge_use_prebuilt | bool)
- name: Extract XWorkmate Go ACP server binary for OpenCode
ansible.builtin.unarchive:
src: "/tmp/xworkmate-bridge-opencode.tar.gz"
dest: "{{ acp_opencode_bridge_binary_path | dirname }}"
remote_src: true
extra_opts:
- "--strip-components=2"
- "xworkmate-bridge/bin/xworkmate-go-core"
owner: root
group: root
mode: "0755"

View File

@ -25,13 +25,10 @@ gateway_openclaw_install_dir: "{{ gateway_openclaw_home }}/.local/lib/node_modul
gateway_openclaw_required_version: "2026.6.1"
gateway_openclaw_npm_package_spec: "openclaw@{{ gateway_openclaw_required_version }}"
gateway_openclaw_global_npm_dir: "{{ gateway_openclaw_home }}/.openclaw/npm"
gateway_openclaw_multi_session_plugin_package_spec: "github:x-evor/openclaw-multi-session-plugins#main"
gateway_openclaw_multi_session_plugin_archive_url: "https://github.com/ai-workspace-lab/openclaw-multi-session-plugins/releases/latest/download/openclaw-multi-session-plugins-runtime-all.tar.gz"
gateway_openclaw_required_global_plugins:
- name: "@openclaw/codex"
version: "{{ gateway_openclaw_required_version }}"
- name: "openclaw-multi-session-plugins"
version: "{{ gateway_openclaw_required_version }}"
package_spec: "{{ gateway_openclaw_multi_session_plugin_package_spec }}"
gateway_openclaw_removed_global_plugins:
- "@openclaw/acpx"
gateway_openclaw_extension_dependency_dirs: []

View File

@ -90,6 +90,32 @@
- not ansible_check_mode
notify: Restart openclaw gateway
- name: Ensure OpenClaw extensions directory exists
ansible.builtin.file:
path: "{{ gateway_openclaw_home }}/.openclaw/extensions"
state: directory
owner: "{{ gateway_openclaw_service_user }}"
group: "{{ gateway_openclaw_service_group }}"
mode: "0755"
become: "{{ ansible_os_family != 'Darwin' }}"
- name: Download OpenClaw Multi-Session Plugins offline archive
ansible.builtin.get_url:
url: "{{ gateway_openclaw_multi_session_plugin_archive_url }}"
dest: "/tmp/openclaw-multi-session-plugins.tar.gz"
mode: "0644"
- name: Extract OpenClaw Multi-Session Plugins
ansible.builtin.unarchive:
src: "/tmp/openclaw-multi-session-plugins.tar.gz"
dest: "{{ gateway_openclaw_home }}/.openclaw/extensions"
remote_src: true
owner: "{{ gateway_openclaw_service_user }}"
group: "{{ gateway_openclaw_service_group }}"
mode: "0755"
become: "{{ ansible_os_family != 'Darwin' }}"
notify: Restart openclaw gateway
- name: Ensure OpenClaw global plugin npm directory exists
ansible.builtin.file:
path: "{{ gateway_openclaw_global_npm_dir }}"

View File

@ -13,24 +13,14 @@
xworkspace_console_home: "{{ ansible_env.HOME | default('/home/ubuntu') }}"
xworkspace_console_root: "{{ xworkspace_console_home }}/.local/state/ai-workspace"
xworkspace_console_repo_dir: "{{ xworkspace_console_home }}/xworkspace-console"
xworkspace_console_source_repo: "https://github.com/ai-workspace-lab/xworkspace-console.git"
xworkspace_console_source_version: "main"
xworkspace_console_source_repo_safe_dir: >-
{{
(xworkspace_console_source_repo | regex_replace('^file://', ''))
if xworkspace_console_source_repo is match('^file://')
else ''
}}
xworkspace_console_runtime_archive: "{{ lookup('ansible.builtin.env', 'XWORKSPACE_CONSOLE_RUNTIME_ARCHIVE') | default('', true) }}"
ai_workspace_prebuilt_components_required: "{{ lookup('ansible.builtin.env', 'AI_WORKSPACE_PREBUILT_COMPONENTS_REQUIRED') | default('false', true) | bool }}"
xworkspace_console_dashboard_dir: "{{ xworkspace_console_repo_dir }}/dashboard"
xworkspace_console_api_dir: "{{ xworkspace_console_repo_dir }}/api"
xworkspace_console_api_binary: "{{ xworkspace_console_repo_dir }}/bin/xworkspace-api"
xworkspace_console_runtime_marker: "{{ xworkspace_console_repo_dir }}/.runtime-archive-sha256"
xworkspace_console_api_working_dir: >-
{{ xworkspace_console_repo_dir if xworkspace_console_runtime_archive | length > 0 else xworkspace_console_api_dir }}
xworkspace_console_api_exec: >-
{{ xworkspace_console_api_binary if xworkspace_console_runtime_archive | length > 0 else '/usr/bin/env go run .' }}
xworkspace_console_api_working_dir: "{{ xworkspace_console_repo_dir }}"
xworkspace_console_api_exec: "{{ xworkspace_console_api_binary }}"
xworkspace_console_scripts_dir: "{{ xworkspace_console_root }}/scripts"
xworkspace_console_config_dir: "{{ xworkspace_console_home }}/.config/xworkspace"
xworkspace_console_url: http://127.0.0.1:17000
@ -498,36 +488,54 @@
--disable-sync \
--new-window
- name: Download XWorkspace Console runtime release
ansible.builtin.get_url:
url: "https://github.com/ai-workspace-lab/xworkspace-console/releases/latest/download/xworkspace-console-runtime-{{ ansible_system | lower }}-{{ 'amd64' if ansible_architecture in ['x86_64', 'amd64'] else 'arm64' }}.tar.gz"
dest: "/tmp/xworkspace-console-runtime.tar.gz"
mode: "0644"
force: true
when: xworkspace_console_runtime_archive | length == 0
- name: Set runtime archive path
ansible.builtin.set_fact:
xworkspace_console_runtime_archive_resolved: "{{ xworkspace_console_runtime_archive if (xworkspace_console_runtime_archive | length > 0) else '/tmp/xworkspace-console-runtime.tar.gz' }}"
- name: Validate packaged XWorkspace Console runtime
ansible.builtin.stat:
path: "{{ xworkspace_console_runtime_archive }}"
path: "{{ xworkspace_console_runtime_archive_resolved }}"
register: xworkspace_console_runtime_archive_stat
when: xworkspace_console_runtime_archive | length > 0
- name: Require packaged XWorkspace Console runtime
ansible.builtin.assert:
that:
- xworkspace_console_runtime_archive | length > 0
- xworkspace_console_runtime_archive_stat.stat.exists | default(false)
fail_msg: "A valid XWORKSPACE_CONSOLE_RUNTIME_ARCHIVE is required in prebuilt-only mode."
when: ai_workspace_prebuilt_components_required
fail_msg: "A valid XWORKSPACE_CONSOLE_RUNTIME_ARCHIVE is required or download failed."
- name: Inspect installed XWorkspace Console runtime marker
ansible.builtin.slurp:
path: "{{ xworkspace_console_runtime_marker }}"
register: xworkspace_console_runtime_marker_content
failed_when: false
when: xworkspace_console_runtime_archive | length > 0
- name: Stop xworkspace-console services before extracting
ansible.builtin.shell: |
uid="$(id -u {{ xworkspace_console_user }})"
systemctl start "user@${uid}.service" || true
for svc in xworkspace-status.timer xworkspace-status.service xworkspace-console.service; do
runuser -u {{ xworkspace_console_user }} -- env XDG_RUNTIME_DIR="/run/user/${uid}" DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/${uid}/bus" systemctl --user stop "$svc" || true
done
become: true
changed_when: false
when: ansible_os_family != 'Darwin'
- name: Install packaged XWorkspace Console runtime
ansible.builtin.unarchive:
src: "{{ xworkspace_console_runtime_archive }}"
src: "{{ xworkspace_console_runtime_archive_resolved }}"
dest: "{{ xworkspace_console_repo_dir | dirname }}"
remote_src: true
owner: "{{ xworkspace_console_user }}"
group: "{{ 'staff' if ansible_os_family == 'Darwin' else xworkspace_console_user }}"
when:
- xworkspace_console_runtime_archive | length > 0
- xworkspace_console_runtime_archive_stat.stat.exists | default(false)
- >-
(xworkspace_console_runtime_marker_content.content | default('') | b64decode | trim)
@ -543,91 +551,8 @@
mode: "0644"
content: "{{ xworkspace_console_runtime_archive_stat.stat.checksum }}\n"
when:
- xworkspace_console_runtime_archive | length > 0
- xworkspace_console_runtime_archive_stat.stat.exists | default(false)
- name: Trust local XWorkspace Console source repository for Git
ansible.builtin.command:
argv:
- git
- config
- --global
- --add
- safe.directory
- "{{ xworkspace_console_source_repo_safe_dir }}"
become_user: "{{ xworkspace_console_user }}"
changed_when: false
when:
- xworkspace_console_runtime_archive | length == 0
- xworkspace_console_source_repo_safe_dir | length > 0
- name: Trust local XWorkspace Console source repository .git directory for Git
ansible.builtin.command:
argv:
- git
- config
- --global
- --add
- safe.directory
- "{{ xworkspace_console_source_repo_safe_dir }}/.git"
become_user: "{{ xworkspace_console_user }}"
changed_when: false
when:
- xworkspace_console_runtime_archive | length == 0
- xworkspace_console_source_repo_safe_dir | length > 0
- name: Stop xworkspace-status timer and services to avoid write conflict on Linux
ansible.builtin.shell: |
uid="$(id -u {{ xworkspace_console_user }})"
systemctl start "user@${uid}.service" || true
for svc in xworkspace-status.timer xworkspace-status.service xworkspace-console.service; do
runuser -u {{ xworkspace_console_user }} -- env XDG_RUNTIME_DIR="/run/user/${uid}" DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/${uid}/bus" systemctl --user stop "$svc" || true
done
become: true
changed_when: false
when:
- ansible_os_family != 'Darwin'
- xworkspace_console_runtime_archive | length == 0
- name: Remove stale xworkspace-console repo to avoid shallow checkout failures
ansible.builtin.file:
path: "{{ xworkspace_console_repo_dir }}"
state: absent
become_user: "{{ xworkspace_console_user }}"
when:
- xworkspace_console_runtime_archive | length == 0
- name: Clone xworkspace-console repository
ansible.builtin.git:
repo: "{{ xworkspace_console_source_repo }}"
dest: "{{ xworkspace_console_repo_dir }}"
version: "{{ xworkspace_console_source_version }}"
force: true
depth: 1
become_user: "{{ xworkspace_console_user }}"
register: xworkspace_console_source_checkout
when: xworkspace_console_runtime_archive | length == 0
- name: Build dashboard assets on target
ansible.builtin.shell: |
set -euo pipefail
cd "{{ xworkspace_console_dashboard_dir }}"
source_commit="$(git -C "{{ xworkspace_console_repo_dir }}" rev-parse HEAD)"
marker=".ai-workspace-build-commit"
if [ -f "dist/index.html" ] && [ "$(cat "$marker" 2>/dev/null || true)" = "$source_commit" ]; then
echo "build=unchanged"
exit 0
fi
npm install && npm run build
printf '%s\n' "$source_commit" > "$marker"
echo "build=changed"
args:
executable: /bin/bash
become_user: "{{ xworkspace_console_user }}"
register: xworkspace_console_dashboard_build
changed_when: "'build=changed' in (xworkspace_console_dashboard_build.stdout | default(''))"
when: xworkspace_console_runtime_archive | length == 0
- name: Deploy AI Workspace portal service configuration
ansible.builtin.copy:
dest: "{{ xworkspace_console_config_dir }}/portal-services.json"