--- - name: Ensure local Hermes ACP build directory exists ansible.builtin.file: path: "{{ acp_hermes_bridge_local_build_dir }}" state: directory mode: "0755" delegate_to: localhost become: false when: not (acp_hermes_bridge_use_prebuilt | bool) - name: Build XWorkmate Go ACP adapter locally for Hermes ansible.builtin.command: cmd: go build -o "{{ acp_hermes_bridge_local_binary_path }}" . chdir: "{{ acp_hermes_bridge_local_source_dir }}" environment: GOOS: "{{ acp_hermes_bridge_build_goos }}" GOARCH: "{{ acp_hermes_bridge_build_goarch }}" CGO_ENABLED: "0" GO111MODULE: "on" delegate_to: localhost become: false check_mode: false when: not (acp_hermes_bridge_use_prebuilt | bool) - name: Inspect Hermes bridge binary attributes ansible.builtin.command: cmd: lsattr "{{ acp_hermes_bridge_binary_path }}" register: acp_hermes_bridge_binary_attrs changed_when: false failed_when: false check_mode: false - name: Remove immutable flag from Hermes bridge binary when present ansible.builtin.command: cmd: chattr -i "{{ acp_hermes_bridge_binary_path }}" when: - ansible_os_family != 'Darwin' - "'i' in (acp_hermes_bridge_binary_attrs.stdout | default(''))" changed_when: true become: true - name: Upload XWorkmate Go ACP adapter binary for Hermes ansible.builtin.copy: src: "{{ acp_hermes_bridge_local_binary_path }}" dest: "{{ acp_hermes_bridge_binary_path }}" owner: "{{ acp_hermes_service_user }}" group: "{{ acp_hermes_service_group }}" mode: "0755" notify: Restart acp hermes when: not (acp_hermes_bridge_use_prebuilt | bool) - name: Restore immutable flag on Hermes bridge binary ansible.builtin.command: cmd: chattr +i "{{ acp_hermes_bridge_binary_path }}" when: - ansible_os_family != 'Darwin' - "'i' in (acp_hermes_bridge_binary_attrs.stdout | default(''))" changed_when: true become: true - name: Ensure Hermes ACP work directories exist ansible.builtin.file: path: "{{ item }}" state: directory owner: "{{ acp_hermes_service_user }}" group: "{{ acp_hermes_service_group }}" mode: "0755" loop: - "{{ acp_hermes_workdir }}" - "{{ acp_hermes_binary_path | dirname }}" - "{{ acp_hermes_xdg_config_home }}" - "{{ acp_hermes_xdg_state_home }}" - name: Install fallback Hermes ACP shim when Hermes binary is absent ansible.builtin.copy: dest: "{{ acp_hermes_binary_path }}" owner: "{{ acp_hermes_service_user }}" group: "{{ acp_hermes_service_group }}" mode: "0755" force: false content: | #!/usr/bin/env python3 import json import sys import uuid def respond(request, result=None, error=None): payload = {"jsonrpc": "2.0", "id": request.get("id")} if error is not None: payload["error"] = {"code": -32000, "message": str(error)} else: payload["result"] = result if result is not None else {} print(json.dumps(payload, separators=(",", ":")), flush=True) for line in sys.stdin: try: request = json.loads(line) except Exception: continue method = request.get("method") if method == "initialize": respond(request, { "protocolVersion": 1, "authMethods": [], "agentCapabilities": { "loadSession": True, "promptCapabilities": {"embeddedContext": True, "image": False}, "sessionCapabilities": {"resume": {}, "fork": {}, "list": {}}, }, }) elif method == "session/new": respond(request, {"sessionId": "hermes-shim-" + uuid.uuid4().hex}) elif method in ("session/prompt", "session/start", "session/message"): params = request.get("params") or {} prompt = params.get("prompt") or params.get("taskPrompt") or "" text = "pong" if "pong" in str(prompt).lower() else "Hermes ACP shim is online." respond(request, {"output": text, "text": text}) else: respond(request, {"ok": True}) notify: Restart acp hermes - name: Deploy Hermes ACP adapter service ansible.builtin.command: cmd: lsattr "/etc/systemd/system/{{ acp_hermes_service_name }}.service" register: acp_hermes_service_attrs changed_when: false failed_when: false check_mode: false when: ansible_os_family != 'Darwin' - name: Remove immutable flag from Hermes ACP systemd service when present ansible.builtin.command: cmd: chattr -i "/etc/systemd/system/{{ acp_hermes_service_name }}.service" when: - ansible_os_family != 'Darwin' - "'i' in (acp_hermes_service_attrs.stdout | default(''))" changed_when: true become: true - name: Read existing Hermes ACP auth token from systemd service ansible.builtin.shell: | set -eu service_path="/etc/systemd/system/{{ acp_hermes_service_name }}.service" if [ -f "$service_path" ]; then sed -n 's/^Environment=HERMES_ADAPTER_AUTH_TOKEN=\(.*\)$/\1/p' "$service_path" | head -n 1 fi args: executable: /bin/sh register: acp_hermes_existing_auth_token changed_when: false failed_when: false no_log: true check_mode: false when: ansible_os_family != 'Darwin' - name: Resolve Hermes ACP auth token ansible.builtin.set_fact: acp_hermes_effective_auth_token: >- {{ acp_hermes_auth_token if (acp_hermes_auth_token | trim | length > 0) else (acp_hermes_existing_auth_token.stdout | default('')) }} no_log: true - name: Deploy Hermes ACP adapter service ansible.builtin.template: src: hermes-acp-adapter.service.j2 dest: "/etc/systemd/system/{{ acp_hermes_service_name }}.service" owner: root group: root mode: "0644" notify: Restart acp hermes when: ansible_os_family != 'Darwin' - name: Restore immutable flag on Hermes ACP systemd service ansible.builtin.command: cmd: chattr +i "/etc/systemd/system/{{ acp_hermes_service_name }}.service" when: - ansible_os_family != 'Darwin' - "'i' in (acp_hermes_service_attrs.stdout | default(''))" changed_when: true become: true - name: Reload systemd manager configuration for Hermes ACP ansible.builtin.systemd: daemon_reload: true when: ansible_os_family != 'Darwin' - name: Ensure Hermes ACP adapter service is enabled and running ansible.builtin.systemd: name: "{{ acp_hermes_service_name }}" enabled: true state: started when: - not ansible_check_mode - ansible_os_family != 'Darwin' - name: Import macOS specific Hermes ACP tasks ansible.builtin.import_tasks: macos.yml when: ansible_os_family == 'Darwin'