# syntax=docker/dockerfile:1.7
ARG HERMES_IMAGE=nousresearch/hermes-agent@sha256:d597ca1f766ff23ff86437fe5e0f36a6049166ce91df917d9577d7418f0767de
FROM ${HERMES_IMAGE}

USER root

ENV PLAYWRIGHT_BROWSERS_PATH=/opt/hermes/.playwright

ARG MCP_PACKAGE=@sellable/mcp@0.1.905
ARG MCP_INTEGRITY=sha512-WBx3m+OWplwYpR3/Kk/fbc3xe33kdP/sarB6aiX426qmyYAL6KvnhIfmA4+pCNkvsfcx9IihC0quFrsaUimUhw==
ARG INSTALLER_PACKAGE=@sellable/install@0.1.702
ARG ADMIN_MCP_PACKAGE=@sellable/admin-mcp@0.1.186-wip.phase158.20260802034727
ARG ADMIN_MCP_INTEGRITY=sha512-qYNew5wd2IfgVcp1UYOG9QvpF/8Mx19YJ5HQtMKzvSfUf3evePjtaKsoXLf2C/GUJ5QlLlHJo84VWOI3V01+9A==
ARG TUS_JS_CLIENT_VERSION=4.3.1
ARG YAML_VERSION=2.9.0
ARG HERMES_VERSION=0.20.4
ARG AGENT_BROWSER_VERSION=0.26.0
ARG TIRITH_VERSION=0.3.3
ARG PLAYWRIGHT_VERSION=1.62.1
ARG PLAYWRIGHT_BROWSER_REVISION=1234
ARG TIRITH_ARCHIVE_SHA256=6cdbe35e8f9ccf42e70ad95b501c93cd218ac18201c3df958d54f6ba0d995ce2
ARG DEFAULT_PROFILE_BUNDLE_FIXTURE_VERSION=1
ARG DEFAULT_PROFILE_BUNDLE_VERSION=1
ARG DEFAULT_PROFILE_BUNDLE_DIGEST=d1e5653304c0d9ad0ca33947711dd359824c0262acfeb11a951336476e2a737d

RUN --mount=type=secret,id=mcp_trust_root,required=true \
    test -s /run/secrets/mcp_trust_root \
    && mkdir -p /usr/local/lib/sellable-agent/external-runtime/mcp \
                /usr/local/share/sellable-agent \
    && test "$(npm view "${MCP_PACKAGE}" dist.integrity)" = "${MCP_INTEGRITY}" \
    && npm install --prefix /usr/local/lib/sellable-agent/external-runtime/mcp \
         --omit=dev --ignore-scripts --no-audit --no-fund "${MCP_PACKAGE}" \
    && test "$(node -p "require('/usr/local/lib/sellable-agent/external-runtime/mcp/node_modules/@sellable/mcp/package.json').version")" = "${MCP_PACKAGE##*@}" \
    && test "$(npm view "${ADMIN_MCP_PACKAGE}" dist.integrity)" = "${ADMIN_MCP_INTEGRITY}" \
    && npm install --prefix /usr/local/lib/sellable-agent/internal-admin-mcp \
         --omit=dev --ignore-scripts --no-audit --no-fund "${ADMIN_MCP_PACKAGE}" \
    && test "$(node -p "require('/usr/local/lib/sellable-agent/internal-admin-mcp/node_modules/@sellable/admin-mcp/package.json').version")" = "${ADMIN_MCP_PACKAGE##*@}" \
    && test -x /usr/local/lib/sellable-agent/internal-admin-mcp/node_modules/.bin/sellable-admin-mcp \
    && npm install --prefix /usr/local/lib/sellable-agent \
         --omit=dev --ignore-scripts --no-audit --no-fund \
         "agent-browser@${AGENT_BROWSER_VERSION}" \
         "tus-js-client@${TUS_JS_CLIENT_VERSION}" "yaml@${YAML_VERSION}" \
    && test "$(node -p "require('/usr/local/lib/sellable-agent/node_modules/agent-browser/package.json').version")" = "${AGENT_BROWSER_VERSION}" \
    && test "$(node -p "require('/usr/local/lib/sellable-agent/node_modules/tus-js-client/package.json').version")" = "${TUS_JS_CLIENT_VERSION}" \
    && test "$(node -p "require('/usr/local/lib/sellable-agent/node_modules/yaml/package.json').version")" = "${YAML_VERSION}" \
    && mkdir -p /usr/local/lib/sellable-agent/external-runtime/mcp/bin \
    && ln -s ../node_modules/.bin/sellable-mcp \
         /usr/local/lib/sellable-agent/external-runtime/mcp/bin/sellable-mcp \
    && test -x /usr/local/lib/sellable-agent/external-runtime/mcp/bin/sellable-mcp \
    && install -o root -g root -m 0444 /run/secrets/mcp_trust_root \
         /usr/local/share/sellable-agent/mcp-turn-trust-root.pem \
    && npm install --prefix /usr/local/lib/sellable-agent/external-runtime/playwright \
         --omit=dev --ignore-scripts --no-audit --no-fund "playwright@${PLAYWRIGHT_VERSION}" \
    && ln -s /usr/local/lib/sellable-agent/external-runtime/playwright/node_modules/.bin/playwright \
         /usr/local/bin/playwright \
    && test "$(playwright --version)" = "Version ${PLAYWRIGHT_VERSION}" \
    && playwright install chromium \
    && test -d "/opt/hermes/.playwright/chromium-${PLAYWRIGHT_BROWSER_REVISION}" \
    && test -d "/opt/hermes/.playwright/chromium_headless_shell-${PLAYWRIGHT_BROWSER_REVISION}" \
    && ln -sf /usr/local/lib/sellable-agent/node_modules/.bin/agent-browser /usr/local/bin/agent-browser \
    && command -v agent-browser >/dev/null \
    && agent-browser --version | grep -F "${AGENT_BROWSER_VERSION}" \
    && /opt/hermes/.venv/bin/python -m ensurepip --upgrade --default-pip \
    && test -x /opt/hermes/.venv/bin/pip \
    && /opt/hermes/.venv/bin/python -m pip --version \
    && uv pip install --python /opt/hermes/.venv/bin/python --no-cache edge-tts==7.2.8 \
    && test "$(/opt/hermes/.venv/bin/python -c "import importlib.metadata; print(importlib.metadata.version('edge-tts'))")" = "7.2.8" \
    && curl --fail --silent --show-error --location \
         --retry 5 --retry-delay 2 --retry-all-errors \
         "https://github.com/sheeki03/tirith/releases/download/v${TIRITH_VERSION}/tirith-x86_64-unknown-linux-gnu.tar.gz" \
         --output /tmp/tirith.tar.gz \
    && echo "${TIRITH_ARCHIVE_SHA256}  /tmp/tirith.tar.gz" | sha256sum --check --strict \
    && tar -xzf /tmp/tirith.tar.gz -C /tmp tirith \
    && install -o root -g root -m 0755 /tmp/tirith /usr/local/bin/tirith \
    && rm -f /tmp/tirith /tmp/tirith.tar.gz \
    && rm -f /etc/s6-overlay/s6-rc.d/user/contents.d/dashboard \
             /etc/s6-overlay/s6-rc.d/user/contents.d/main-hermes \
             /etc/cont-init.d/01-hermes-setup \
             /etc/cont-init.d/015-supervise-perms \
             /etc/cont-init.d/02-reconcile-profiles \
    && npm cache clean --force

COPY mcp-context-proxy.mjs mcp-runtime-binding.mjs fly-customer-model.mjs fly-customer-worker.mjs profile-materializer.mjs hermes-bridge.mjs hermes-memory-snapshot.mjs fly-runtime-identity.mjs fly-soul-bridge.mjs fly-soul-bridge-exec.mjs fly-skills-bridge.mjs fly-skills-bridge-exec.mjs fly-capabilities-bridge.mjs fly-capabilities-bridge-exec.mjs soul-artifact-validator.mjs default-profile-bundle.mjs default-profile-reconciler.mjs fly-cron-proof-exec.mjs model-auth-reconciler.mjs model-auth-canary-reseed.mjs model-health-reporter.mjs \
  /usr/local/lib/sellable-agent/
COPY abandoned-runtime-scratch.mjs /usr/local/lib/sellable-agent/abandoned-runtime-scratch.mjs
COPY default-profile-bundles/shared/ /usr/local/lib/sellable-agent/default-profile-bundles/shared/
COPY default-profile-bundles/customer/ /usr/local/lib/sellable-agent/default-profile-bundles/customer/
COPY default-profile-bundles/fixtures/ /usr/local/lib/sellable-agent/default-profile-bundles/fixtures/
COPY hermes-memory-dirty.mjs /opt/sellable/bin/hermes-memory-dirty
COPY hermes-memory-reconcile.sh /opt/sellable/share/hermes-memory-reconcile.sh
COPY hermes-endpoint-cron.mjs /opt/sellable/bin/hermes-endpoint-cron
COPY fly-customer-image/model-auth-store.mjs /usr/local/lib/sellable-agent/fly-customer-image/model-auth-store.mjs
COPY fly-customer-image/hermes-runs-client.mjs /usr/local/lib/sellable-agent/fly-customer-image/hermes-runs-client.mjs
COPY fly-customer-image/endpoint-uat-completion-gate.mjs /usr/local/lib/sellable-agent/fly-customer-image/endpoint-uat-completion-gate.mjs
COPY fly-customer-image/customer-runtime.mjs /usr/local/lib/sellable-agent/fly-customer-image/customer-runtime.mjs
COPY fly-customer-image/rootfs/ /

RUN set -eux; \
    fixture_args=""; \
    if test -n "${DEFAULT_PROFILE_BUNDLE_FIXTURE_VERSION}"; then \
      fixture_args="--fixture-version ${DEFAULT_PROFILE_BUNDLE_FIXTURE_VERSION}"; \
    fi; \
    node /usr/local/lib/sellable-agent/default-profile-bundle.mjs \
      --kind CUSTOMER ${fixture_args} \
      --output /usr/local/share/sellable-agent/default-profile-bundle \
    && node -e \
      'const fs=require("fs"); const manifest=JSON.parse(fs.readFileSync("/usr/local/share/sellable-agent/default-profile-bundle/manifest.json")); if(String(manifest.bundleVersion)!==process.argv[1] || manifest.bundleDigest!==process.argv[2]) process.exit(1);' \
      "${DEFAULT_PROFILE_BUNDLE_VERSION}" "${DEFAULT_PROFILE_BUNDLE_DIGEST}" \
    && node --input-type=module -e \
      'import { installHermesAgentBridge, HERMES_AGENT_BRIDGE_DEDICATED_V020_CONTRACT } from "/usr/local/lib/sellable-agent/hermes-bridge.mjs"; installHermesAgentBridge({ sourceRoot: "/opt/hermes", contract: HERMES_AGENT_BRIDGE_DEDICATED_V020_CONTRACT });' \
    && node --input-type=module -e \
      'await import("/usr/local/lib/sellable-agent/fly-runtime-identity.mjs");' \
    && node --input-type=module -e \
      'await import("/usr/local/lib/sellable-agent/fly-customer-image/customer-runtime.mjs");' \
    && printf '%s\n' \
      '#!/usr/bin/env node' \
      'import("file:///usr/local/lib/sellable-agent/fly-soul-bridge.mjs").then(({ runSoulBridgeCli }) => runSoulBridgeCli());' \
      > /usr/local/bin/sellable-soul-bridge \
    && chmod 0555 /usr/local/bin/sellable-soul-bridge \
    && printf '%s\n' \
      '#!/usr/bin/env node' \
      'import("file:///usr/local/lib/sellable-agent/fly-soul-bridge-exec.mjs").then(({ runFlySoulBridgeExecCli }) => runFlySoulBridgeExecCli());' \
      > /usr/local/bin/sellable-soul-bridge-exec \
    && chmod 0555 /usr/local/bin/sellable-soul-bridge-exec \
    && printf '%s\n' \
      '#!/usr/bin/env node' \
      'import("file:///usr/local/lib/sellable-agent/fly-skills-bridge-exec.mjs").then(({ runFlySkillsBridgeExecCli }) => runFlySkillsBridgeExecCli());' \
      > /usr/local/bin/sellable-skills-bridge-exec \
    && chmod 0555 /usr/local/bin/sellable-skills-bridge-exec \
    && printf '%s\n' \
      '#!/usr/bin/env node' \
      'import("file:///usr/local/lib/sellable-agent/fly-capabilities-bridge-exec.mjs").then(({ runFlyCapabilitiesBridgeExecCli }) => runFlyCapabilitiesBridgeExecCli());' \
      > /usr/local/bin/sellable-capabilities-bridge-exec \
    && chmod 0555 /usr/local/bin/sellable-capabilities-bridge-exec \
    && sha256sum /usr/local/lib/sellable-agent/fly-soul-bridge.mjs \
      > /usr/local/share/sellable-agent/soul-bridge-source.sha256 \
    && sha256sum /usr/local/lib/sellable-agent/fly-skills-bridge.mjs \
      /usr/local/lib/sellable-agent/fly-skills-bridge-exec.mjs \
      > /usr/local/share/sellable-agent/skills-bridge-source.sha256 \
    && sha256sum /usr/local/lib/sellable-agent/default-profile-reconciler.mjs \
      /usr/local/lib/sellable-agent/fly-cron-proof-exec.mjs \
      > /usr/local/share/sellable-agent/default-profile-reconcile-source.sha256 \
    && sha256sum /usr/local/lib/sellable-agent/fly-capabilities-bridge.mjs \
      /usr/local/lib/sellable-agent/fly-capabilities-bridge-exec.mjs \
      > /usr/local/share/sellable-agent/capabilities-bridge-source.sha256 \
    && chmod 0444 /usr/local/share/sellable-agent/soul-bridge-source.sha256 \
      /usr/local/share/sellable-agent/skills-bridge-source.sha256 \
      /usr/local/share/sellable-agent/default-profile-reconcile-source.sha256 \
      /usr/local/share/sellable-agent/capabilities-bridge-source.sha256 \
    && chmod 0755 /etc \
    && chmod 0555 /usr/local/lib/sellable-agent/*.mjs \
    && chmod 0555 /opt/sellable/bin/hermes-memory-dirty /opt/sellable/bin/hermes-endpoint-cron \
    && chmod 0444 /opt/sellable/share/hermes-memory-reconcile.sh \
    && chmod 0555 /etc/s6-overlay/s6-rc.d/customer-runtime/run \
    && chmod 0444 /etc/s6-overlay/s6-rc.d/customer-runtime/type \
                  /etc/s6-overlay/s6-rc.d/user/contents.d/customer-runtime

LABEL io.sellable.runtime.kind="customer" \
      io.sellable.runtime.listener="native-dedicated-slack" \
      io.sellable.runtime.api-server="authenticated-loopback-127.0.0.1:8642" \
      io.sellable.runtime.installers="build-only" \
      io.sellable.runtime.default-profile-bundle-version="${DEFAULT_PROFILE_BUNDLE_VERSION}" \
      io.sellable.runtime.default-profile-bundle-digest="${DEFAULT_PROFILE_BUNDLE_DIGEST}"

ENV HOME=/opt/data \
    HERMES_HOME=/opt/data \
    HERMES_WRITE_SAFE_ROOT=/opt/data \
    TIRITH_BIN=/usr/local/bin/tirith \
    NODE_ENV=production \
    SELLABLE_AGENT_RUNTIME=1 \
    SELLABLE_AGENT_HERMES_VERSION=${HERMES_VERSION} \
    SELLABLE_AGENT_INSTALLER_PACKAGE=${INSTALLER_PACKAGE} \
    SELLABLE_AGENT_MCP_PACKAGE=${MCP_PACKAGE} \
    SELLABLE_AGENT_DEFAULT_PROFILE_BUNDLE_VERSION=${DEFAULT_PROFILE_BUNDLE_VERSION} \
    SELLABLE_AGENT_DEFAULT_PROFILE_BUNDLE_DIGEST=${DEFAULT_PROFILE_BUNDLE_DIGEST} \
    SELLABLE_AGENT_DEFAULT_PROFILE_FIXTURE_TEST_ONLY=1 \
    SELLABLE_AGENT_DEFAULT_PROFILE_FIXTURE_WORKSPACE_ID=cmp6h5wo00000l204a6g2jrk1 \
    SELLABLE_AGENT_DEFAULT_PROFILE_FIXTURE_AGENT_ID=agent_6bed1d07c8892cde4a308a4c54d8bd14 \
    SELLABLE_AGENT_PLAYWRIGHT_VERSION=${PLAYWRIGHT_VERSION} \
    SELLABLE_AGENT_PLAYWRIGHT_BROWSER_REVISION=${PLAYWRIGHT_BROWSER_REVISION} \
    PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1

ENTRYPOINT ["/init"]
