--- - name: "Agents | Resolve catalog entry | {{ _agent_key }}" ansible.builtin.set_fact: _agent: "{{ multica_agent_cli_catalog[_agent_key] }}" - name: "Agents | Read the installed version | {{ _agent_key }}" ansible.builtin.command: argv: ["/bin/sh", "-c", "command -v {{ _agent.binary }} >/dev/null 2>&1 && {{ _agent.version_command }}"] become: true become_user: "{{ multica_user }}" environment: "{{ _multica_user_env }}" register: _agent_installed changed_when: false failed_when: false check_mode: false # Version formats differ per CLI ("2.1.304 (Claude Code)", "Hermes Agent # v0.21.5+..."), so this matches the pinned version anywhere in the output — # but on a version-component boundary. A plain substring test would accept # 2.1.3045 for a pin of 2.1.304, and silently never upgrade. - name: "Agents | Decide whether an install is needed | {{ _agent_key }}" ansible.builtin.set_fact: _agent_needs_install: >- {{ _agent_installed.rc != 0 or (_agent.package_version | default('') | length > 0 and not ((_agent_installed.stdout | default('')) is search( '(^|[^0-9.])' ~ (_agent.package_version | regex_escape) ~ '([^0-9.]|$)'))) }} - name: "Agents | Install via npm as the daemon user | {{ _agent_key }}" ansible.builtin.command: argv: - "{{ multica_install_dir }}/npm" - install - --global - --no-fund - --no-audit - "{{ _agent.package }}{{ ('@' ~ _agent.package_version) if _agent.package_version | default('') | length > 0 else '' }}" become: true become_user: "{{ multica_user }}" environment: "{{ _multica_user_env }}" when: _agent_needs_install | bool changed_when: true notify: restart multica daemon - name: "Agents | Resolve and link onto the default PATH | {{ _agent_key }}" ansible.builtin.include_tasks: _link.yml