Compare commits
1 Commits
main
...
release/v1
| Author | SHA1 | Date | |
|---|---|---|---|
| 0007981f6d |
@ -11,10 +11,6 @@ acp_opencode_workdir: "{{ ansible_env.HOME | default('/home/' + acp_opencode_ser
|
||||
# user-level npm global bin lives under ~/.local/bin; include Homebrew + system.
|
||||
acp_opencode_npm_global_bin: "{{ acp_opencode_home + '/.local/bin' if ansible_os_family == 'Darwin' else '/usr/bin' }}"
|
||||
acp_opencode_path: "{{ acp_opencode_npm_global_bin }}:/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/usr/local/sbin:/usr/bin:/bin"
|
||||
# OpenCode CLI binary the adapter spawns lazily (mirrors gemini/codex which use
|
||||
# {{ acp_X_npm_global_bin }}/<cli>). Was hardcoded to /usr/bin/opencode in the
|
||||
# unit template; use the resolved npm global bin so macOS (~/.local/bin) works too.
|
||||
acp_opencode_binary_path: "{{ acp_opencode_npm_global_bin }}/opencode"
|
||||
acp_opencode_listen_host: 127.0.0.1
|
||||
acp_opencode_listen_port: 38992
|
||||
acp_opencode_packages: []
|
||||
|
||||
@ -79,29 +79,6 @@
|
||||
- "{{ acp_opencode_home }}/.local"
|
||||
- "{{ acp_opencode_workdir }}"
|
||||
|
||||
# Resolve the OpenCode CLI at deploy time instead of assuming a fixed path.
|
||||
# npm installs it wherever the active node prefix points (NodeSource -> /usr/bin
|
||||
# on Debian/Ubuntu, ~/.local/bin or Homebrew on macOS), so probe the real path
|
||||
# with the role PATH and fall back to the OS-aware default when not yet present.
|
||||
- name: Resolve OpenCode CLI binary path
|
||||
ansible.builtin.shell: |
|
||||
set -eu
|
||||
export PATH="{{ acp_opencode_path }}:${PATH}"
|
||||
command -v opencode || true
|
||||
args:
|
||||
executable: /bin/bash
|
||||
register: acp_opencode_resolved_bin
|
||||
changed_when: false
|
||||
|
||||
- name: Use resolved OpenCode CLI binary path when present
|
||||
ansible.builtin.set_fact:
|
||||
acp_opencode_binary_path: "{{ acp_opencode_resolved_bin.stdout_lines[0] | trim }}"
|
||||
when: acp_opencode_resolved_bin.stdout | default('') | trim | length > 0
|
||||
|
||||
- name: Report effective OpenCode CLI binary path
|
||||
ansible.builtin.debug:
|
||||
msg: "OpenCode CLI binary resolved to: {{ acp_opencode_binary_path }}"
|
||||
|
||||
- name: Deploy Caddy main file
|
||||
ansible.builtin.template:
|
||||
src: Caddyfile.j2
|
||||
|
||||
@ -20,68 +20,33 @@
|
||||
# 用 curl 重试循环替代 uri:服务刚 (重)启时 adapter 会先 accept TCP 但短时间内不
|
||||
# 应答(读挂起),而 uri 默认 30s 超时 + retries/until 在连接超时上不可靠循环(实测
|
||||
# 仅试一次即失败)。每次 5s 上限、真重试,给冷启动足够时间(adapter 就绪后 ~4ms 回 200)。
|
||||
# 包在 block/rescue:探针失败时把 systemctl status + journalctl 打到 CI 日志,
|
||||
# 否则 play 在此中止,看不到 adapter 进程真正的崩溃原因(如 last code 000)。
|
||||
- name: Validate OpenCode local ACP endpoint
|
||||
block:
|
||||
- name: Validate OpenCode local ACP endpoint (readiness retry)
|
||||
ansible.builtin.shell: |
|
||||
set -eu
|
||||
url="http://{{ acp_opencode_listen_host }}:{{ acp_opencode_listen_port }}/acp/rpc"
|
||||
body='{"jsonrpc":"2.0","id":1,"method":"acp.capabilities","params":{}}'
|
||||
code=""
|
||||
for i in $(seq 1 30); do
|
||||
code="$(curl -s -m 5 -o /dev/null -w '%{http_code}' -X POST "$url" \
|
||||
-H 'Content-Type: application/json' -d "$body" 2>/dev/null || true)"
|
||||
if [ "$code" = "200" ]; then
|
||||
echo "OpenCode ACP endpoint ready after ${i} attempt(s)"
|
||||
exit 0
|
||||
fi
|
||||
sleep 2
|
||||
done
|
||||
echo "OpenCode ACP endpoint ${url} not ready after retries (last code: ${code:-none})" >&2
|
||||
exit 1
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: false
|
||||
register: acp_opencode_adapter_probe
|
||||
rescue:
|
||||
- name: Capture OpenCode ACP service status on failure
|
||||
ansible.builtin.command: systemctl status "{{ acp_opencode_service_name }}" --no-pager --full
|
||||
register: acp_opencode_status_fail
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
when: ansible_os_family != 'Darwin'
|
||||
|
||||
- name: Capture recent OpenCode ACP service logs on failure
|
||||
ansible.builtin.command: journalctl -u "{{ acp_opencode_service_name }}" -n 80 --no-pager
|
||||
register: acp_opencode_journal_fail
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
when: ansible_os_family != 'Darwin'
|
||||
|
||||
- name: Show OpenCode ACP failure diagnostics
|
||||
ansible.builtin.debug:
|
||||
msg:
|
||||
- "Probe stderr: {{ acp_opencode_adapter_probe.stderr | default('N/A') }}"
|
||||
- "Listeners: {{ acp_opencode_ss.stdout | default('N/A') }}"
|
||||
- "Service status: {{ acp_opencode_status_fail.stdout | default('N/A') }}"
|
||||
- "Recent logs: {{ acp_opencode_journal_fail.stdout | default('N/A') }}"
|
||||
|
||||
- name: Fail after emitting OpenCode ACP diagnostics
|
||||
ansible.builtin.fail:
|
||||
msg: >-
|
||||
OpenCode ACP endpoint
|
||||
{{ acp_opencode_listen_host }}:{{ acp_opencode_listen_port }} did not
|
||||
become ready. See the diagnostics above (service status + journal) for
|
||||
the adapter crash cause.
|
||||
- name: Validate OpenCode local ACP endpoint (readiness retry)
|
||||
ansible.builtin.shell: |
|
||||
set -eu
|
||||
url="http://{{ acp_opencode_listen_host }}:{{ acp_opencode_listen_port }}/acp/rpc"
|
||||
body='{"jsonrpc":"2.0","id":1,"method":"acp.capabilities","params":{}}'
|
||||
code=""
|
||||
for i in $(seq 1 30); do
|
||||
code="$(curl -s -m 5 -o /dev/null -w '%{http_code}' -X POST "$url" \
|
||||
-H 'Content-Type: application/json' -d "$body" 2>/dev/null || true)"
|
||||
if [ "$code" = "200" ]; then
|
||||
echo "OpenCode ACP endpoint ready after ${i} attempt(s)"
|
||||
exit 0
|
||||
fi
|
||||
sleep 2
|
||||
done
|
||||
echo "OpenCode ACP endpoint ${url} not ready after retries (last code: ${code:-none})" >&2
|
||||
exit 1
|
||||
args:
|
||||
executable: /bin/bash
|
||||
changed_when: false
|
||||
register: acp_opencode_adapter_probe
|
||||
|
||||
- name: Show OpenCode ACP status
|
||||
ansible.builtin.command: systemctl status "{{ acp_opencode_service_name }}" --no-pager
|
||||
register: acp_opencode_status
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
when: ansible_os_family != 'Darwin'
|
||||
|
||||
- name: Show OpenCode ACP validation summary
|
||||
ansible.builtin.debug:
|
||||
@ -90,6 +55,6 @@
|
||||
- "Preferred WebSocket endpoint: {{ acp_opencode_public_base_url }}/acp"
|
||||
- "Compatibility HTTP RPC endpoint: {{ acp_opencode_public_base_url }}/acp/rpc"
|
||||
- "OpenCode ACP adapter listener: {{ acp_opencode_listen_host }}:{{ acp_opencode_listen_port }}"
|
||||
- "Readiness probe: {{ acp_opencode_adapter_probe.stdout | default('N/A') }}"
|
||||
- "Service: {{ acp_opencode_status.stdout | default('N/A') }}"
|
||||
- "Socket: {{ acp_opencode_ss.stdout | default('N/A') }}"
|
||||
- "Adapter capabilities HTTP: {{ acp_opencode_adapter_http.content | default('N/A') }}"
|
||||
|
||||
@ -0,0 +1,27 @@
|
||||
[Unit]
|
||||
Description=XWorkmate OpenCode ACP bridge server
|
||||
After=network-online.target {{ acp_opencode_service_name }}.service
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User={{ acp_opencode_service_user }}
|
||||
Group={{ acp_opencode_service_group }}
|
||||
WorkingDirectory={{ acp_opencode_workdir }}
|
||||
Environment=HOME={{ acp_opencode_home }}
|
||||
Environment=TERM=xterm-256color
|
||||
Environment=ACP_LISTEN_ADDR={{ acp_opencode_bridge_listen_host }}:{{ acp_opencode_bridge_listen_port }}
|
||||
Environment=ACP_ALLOWED_ORIGINS={{ acp_opencode_bridge_allowed_origins | join(',') }}
|
||||
{% if acp_opencode_auth_token | trim | length > 0 %}
|
||||
Environment=ACP_AUTH_TOKEN={{ acp_opencode_auth_token }}
|
||||
{% endif %}
|
||||
Environment=ACP_CODEX_BIN={{ acp_opencode_bridge_disabled_binary_path }}
|
||||
Environment=ACP_CLAUDE_BIN={{ acp_opencode_bridge_disabled_binary_path }}
|
||||
Environment=ACP_GEMINI_BIN={{ acp_opencode_bridge_disabled_binary_path }}
|
||||
Environment=ACP_OPENCODE_BIN={{ acp_opencode_bridge_opencode_binary_path }}
|
||||
ExecStart={{ acp_opencode_bridge_binary_path }} serve --listen {{ acp_opencode_bridge_listen_host }}:{{ acp_opencode_bridge_listen_port }}
|
||||
Restart=always
|
||||
RestartSec=2
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@ -9,10 +9,9 @@ User={{ acp_opencode_service_user }}
|
||||
Group={{ acp_opencode_service_group }}
|
||||
WorkingDirectory={{ acp_opencode_workdir }}
|
||||
Environment=HOME={{ acp_opencode_home }}
|
||||
Environment=PATH={{ acp_opencode_path }}
|
||||
Environment=TERM=xterm-256color
|
||||
Environment=OPENCODE_ADAPTER_ALLOWED_ORIGINS={{ acp_opencode_bridge_allowed_origins | join(',') }}
|
||||
ExecStart={{ acp_opencode_bridge_binary_path }} adapter opencode --listen {{ acp_opencode_listen_host }}:{{ acp_opencode_listen_port }} --opencode-bin {{ acp_opencode_binary_path }} --cwd {{ acp_opencode_workdir }}
|
||||
ExecStart={{ acp_opencode_bridge_binary_path }} adapter opencode --listen {{ acp_opencode_listen_host }}:{{ acp_opencode_listen_port }} --opencode-bin /usr/bin/opencode --cwd {{ acp_opencode_workdir }}
|
||||
Restart=always
|
||||
RestartSec=2
|
||||
|
||||
|
||||
@ -17,7 +17,6 @@
|
||||
|
||||
exec "{{ acp_opencode_bridge_binary_path }}" adapter opencode \
|
||||
-listen {{ acp_opencode_listen_host }}:{{ acp_opencode_listen_port }} \
|
||||
-opencode-bin "{{ acp_opencode_binary_path }}" \
|
||||
-cwd "{{ acp_opencode_workdir }}"
|
||||
</string>
|
||||
</array>
|
||||
|
||||
@ -6,16 +6,6 @@ migrate_litellm_db: "litellm"
|
||||
migrate_litellm_db_user: "litellm"
|
||||
migrate_litellm_db_host: "127.0.0.1"
|
||||
|
||||
# Public bootstrap redirects
|
||||
ai_workspace_caddy_base_dir: "{{ caddy_config_dir | default('/etc/caddy') }}"
|
||||
ai_workspace_caddy_conf_dir: "{{ ai_workspace_caddy_base_dir }}/conf.d"
|
||||
ai_workspace_caddyfile_path: "{{ ai_workspace_caddy_base_dir }}/Caddyfile"
|
||||
ai_workspace_caddy_fragment_path: "{{ ai_workspace_caddy_conf_dir }}/install.svc.plus.caddy"
|
||||
ai_workspace_public_domain: "install.svc.plus"
|
||||
ai_workspace_install_script_url: "https://raw.githubusercontent.com/ai-workspace-lab/xworkspace-console/main/scripts/setup-ai-workspace-all-in-one.sh"
|
||||
ai_workspace_xworkmate_install_script_url: "https://raw.githubusercontent.com/ai-workspace-lab/xworkmate-app/main/scripts/install-xworkmate-app.sh"
|
||||
ai_workspace_manage_caddy: true
|
||||
|
||||
# Migration paths
|
||||
openclaw_data_dir: "~/.openclaw"
|
||||
xworkspace_state_dir: "~/.local/state/xworkspace"
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
---
|
||||
dependencies:
|
||||
- role: roles/vhosts/caddy
|
||||
- role: roles/agent_skills
|
||||
- role: roles/vhosts/gateway_openclaw
|
||||
- role: roles/vhosts/xworkmate_bridge
|
||||
|
||||
@ -1,35 +1,4 @@
|
||||
---
|
||||
- name: Ensure AI Workspace Caddy fragment directory exists
|
||||
ansible.builtin.file:
|
||||
path: "{{ ai_workspace_caddy_conf_dir }}"
|
||||
state: directory
|
||||
mode: "0755"
|
||||
when: ai_workspace_manage_caddy | bool
|
||||
|
||||
- name: Render install.svc.plus redirect fragment
|
||||
ansible.builtin.template:
|
||||
src: Caddyfile.j2
|
||||
dest: "{{ ai_workspace_caddy_fragment_path }}"
|
||||
mode: "0644"
|
||||
register: ai_workspace_caddy_fragment
|
||||
when: ai_workspace_manage_caddy | bool
|
||||
|
||||
- name: Validate Caddy configuration
|
||||
ansible.builtin.command: >-
|
||||
caddy validate --config {{ ai_workspace_caddyfile_path }}
|
||||
changed_when: false
|
||||
when:
|
||||
- ai_workspace_manage_caddy | bool
|
||||
- ai_workspace_caddy_fragment.changed
|
||||
|
||||
- name: Reload Caddy after updating install redirects
|
||||
ansible.builtin.service:
|
||||
name: caddy
|
||||
state: reloaded
|
||||
when:
|
||||
- ai_workspace_manage_caddy | bool
|
||||
- ai_workspace_caddy_fragment.changed
|
||||
|
||||
# =============================================================================
|
||||
# Final deployment of the prebuilt XWorkspace Console runtime.
|
||||
#
|
||||
|
||||
@ -1,6 +0,0 @@
|
||||
{{ ai_workspace_public_domain }} {
|
||||
redir /ai-workspace {{ ai_workspace_install_script_url }} 302
|
||||
redir /ai-workspace/latest {{ ai_workspace_install_script_url }} 302
|
||||
redir /xworkmate-app {{ ai_workspace_xworkmate_install_script_url }} 302
|
||||
redir /xworkmate-app/latest {{ ai_workspace_xworkmate_install_script_url }} 302
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user